You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
106 lines
27 KiB
106 lines
27 KiB
import { addBanner, addArticle, addTitle, addHeader, addParagraph, addClassParagraph, addSubHeader, addOrderedList, addUnorderedList, addBlockquote, addInset, addInsetList, addInsetCodeListing, addInsetBulletList, addImageWithCaption, addButtonGroup, addSidebar, addSyntax, menu, global_menu } from '/scripts/import.js'; |
|
|
|
const heading = document.querySelector(".heading"); |
|
const global = document.querySelector(".global_menu"); |
|
const local = document.querySelector(".local_menu"); |
|
const sidebar = document.querySelector(".sidebar"); |
|
const main = document.querySelector(".main_content"); |
|
|
|
heading.append(addTitle("CSS Layouts from Float to Flexbox and Grid")); |
|
heading.append(addParagraph("Christina Truong - LinkedIn Learning - September 2019")); |
|
heading.append(addParagraph("Chapter 3 - Grid")); |
|
|
|
main.append(addHeader("Grid vs Flexbox")); |
|
main.append(addParagraph("When we looked at flexbox, we saw that it is a one-dimensional layout although it is possible to create a two dimensional layout. With grid, the module is designed to allow you to create a two dimensional layout so that is the biggest and most obvious difference between the two. Where flexbox replaced floats and made them largely redundant, grid should be seen as more of a complementary layout rather than a replacement.")); |
|
main.append(addParagraph("For example, with our exercise layout, if we were to implement this with grid (which we will do later), we might choose to use a flexbox for the navigation bar which is a one dimensional layout (in other words a column) within the overall two dimensional layout.")); |
|
main.append(addParagraph("So both layouts can be useful and can be combined and both have their uses. Flexbox is better if you need a one dimensional layout but with grid, you can lay out elements in both dimensions at the same time so it is better for creating two dimensional layouts.")); |
|
main.append(addHeader("Grid, Grid Systems and CSS Grid")); |
|
main.append(addParagraph("In the context of design, a grid is a pattern used to line up elements and to help produce a consistent layout. It breaks the horizontal space into a number of evenly spaced columns of the same width. There might also be rows to help create a two dimensional layout.")); |
|
main.append(addParagraph("This is typical of the sort of layout you would find in a newspaper which is traditionally arranged in columns (you will hear this reflected in 'newspaper-speak' in which, for example, regularly appearing mains are referred to as 'columns'). You will also often see some elements such as a photo or a separate box with something like a commentary, that spans more than one of the columns. CSS layouts including grid, flex and float are intended to allow this type of layout to be produced on a webpage.")); |
|
main.append(addParagraph("This might not be the best example so I should point out that I am not trying to propose a good layout, this is just intended to act as an example of how we can use a grid to produce an effective layout. We will see how grid works in CSS and how we can achieve the layout we want with it.")); |
|
main.append(addParagraph("The following are screenshots from the course video which will hopefully make things clearer. First of all, a pretty standard layout.")); |
|
main.append(addImageWithCaption("./images/grid1.jpg", "A standard grid layout.")); |
|
main.append(addParagraph("This shows a layout with 12 columns and two rows. The white spaces between the columns are called gutters and these allow us to evenly space the columns. The darker blue areas are the gutters between the rows. We can use a grid to create more complicated layouts.")); |
|
main.append(addImageWithCaption("./images/grid2.jpg", "A standard grid layout.")); |
|
main.append(addParagraph("We have been able to achieve layouts like these using older techniques, including flex and the flex exercise was a good example of this. We would generally do that by positioning items in the page block-by-block and sizing them according to our needs.")); |
|
main.append(addParagraph("A CSS grid, by which we mean a grid created with the CSS module, uses pre-defined rules which are associated with pre-defined class names so we can take advantage of these by creating elements with those class names. For example, let's say we want an element to span 4 columns. We would give it the class name")); |
|
main.append(addSyntax("col-4")); |
|
main.append(addParagraph("Similarly, if we wanted an element to span 8 columns, we would give it the class name")); |
|
main.append(addSyntax("col-8")); |
|
main.append(addParagraph("There are a number of 3rd party products that provide you with either a simple grid template or a complete framework, the most well-known of these is probably <a href='https://getbootstrap.com/'>Bootstrap</a> but there are a number of others. For example, you can find a list of these at namecheap.com in an main entitled <a href='https://www.namecheap.com/blog/top-15-css-3-grid-systems/'>Top 15 HTML 5 / CSS 3 grid systems & frameworks</a> and a simple Google search will find other similar lists.")); |
|
main.append(addParagraph("There are pros and cons to using these. When I was starting out on my degree course in 2013, neither flexbox nor grid had been introduced to CSS yet. At that time, Bootstrap was probably the most popular framework and may still be. so it was taught in the first Web Development classes I took. I seem to recall it was pretty easy to work with but it added a lot of code to your project. If you download the latest version, for example, which is currently 5.3.0 as at 6 June 2023, the unzipped framework is around 18-20 MB and includes 745 files in 111 directories. In terms of size, this doesn't sound like a huge amount but to put into some sort of context, the Web Development section on this site currently comprises notes on around a dozen courses and is around 90 MB and includes 863 files in 155 directories.")); |
|
main.append(addParagraph("Not surprisingly, one of the disadvantages of this type of framework is code-bloat which can be an issue if you have a small website where keeping the overall size small is important. Having said that, disk space isn't as much of a problem as it has been in the past and this was true in 2013 as well.")); |
|
main.append(addParagraph("Possibly a more serious drawback would be any restrictions in terms of how you can customise the framework and arguably it adds an additional level of complexity which may be more of an issue. This is particularly true now that we can get a lot of the advantages of a framework by creating a grid layout from scratch. This course doesn't cover frameworks (although there are certainly some Linked in Learning courses covering Bootstrap and one that covers <a href='https://www.linkedin.com/learning/css-frameworks-grids'>CSS Frameworks and Grids</a>).")); |
|
main.append(addParagraph("For the rest of this section, we will cover how to create CSS grids using the grid module.")); |
|
main.append(addHeader("Create a Basic Grid Layout")); |
|
main.append(addParagraph("There are some similarities between grid and flex so soe aspects of creating a grid layout will be familiar. We use grid or inline-grid as the value for our display property in order to designate an element as a grid container and that elements <strong>direct</strong> child elements become grid items.")); |
|
main.append(addParagraph("If you use grid as the value, the grid container will be displayed as a block element so it will be stacked vertically with other elements and will span the width of its container. By default, the grid items will also be displayed as block elements within the grid container because at this stage, we have only defined a container as a grid container, we have applied any grid properties.")); |
|
main.append(addParagraph("as you will probably expect, if you use inline-grid as the value, the grid container will be displayed inline with other inline elements. The grid items will be displayed as block elements within the grid container but their width, which really determines the width of our inline grid container, will be determined by their content.")); |
|
main.append(addParagraph("To start making the elements look like a grid layout, we need to define that grid and our elements will fit into it and we that with a couple of properties. Firstly, we can define the number of rows with something like")); |
|
main.append(addSyntax("grid-template-columns: 100px 100px 100px;")); |
|
main.append(addParagraph("That will define 3 columns, each with a width of 100 pixels. We can similarly use the grid-template-rows property to define rows but we will come back to that, the syntax is thee same. For now, we will get started with creating a grid with an example on <a href='https://codepen.io/Philip64/pen/zYMGqoZ?editors=1100'>codepen.io</a>. Our starting point is a grid container with five grid items.")); |
|
main.append(addImageWithCaption("./images/grid3.jpg", "Demonstrating grid - the starting point of our codepen demo.")); |
|
main.append(addParagraph("At this stage, we have created a grid containing five grid items but we haven't added any grid properties. You can confirm that by commenting out the display property that defines the grid container and you'll see that it makes no difference to how the layout looks.")); |
|
main.append(addParagraph("We will start to define the grid by setting the number of columns to 3, each with a width of 100 pixels and we will also set the number of columns to 2 with a height of 100 pixels.")); |
|
main.append(addImageWithCaption("./images/grid4.jpg", "Demonstrating grid - adding columns and rows to the grid.")); |
|
main.append(addParagraph("Notice that the grid items take up the amount of space specified with the grid-template-columns and grid-template-rows properties. They don't use up the extra space.")); |
|
main.append(addParagraph("The columns (or rows) don't have to be all the same size and we don't have to specify the width in pixels, we can use any CSS units such as percentages or ems and so on. If we have several columns that are all the same size, it can become tedious to type out the same value repeatedly. CSS provides a shorthand for that and that is the repeat function and the function takes two arguments, an integer representing the number of columns and a size for the columns.")); |
|
main.append(addParagraph("For instance, let's say we want to switch from 3 to 4 columns, we could specify the value for grid-template-rows like this")); |
|
main.append(addSyntax("grid-template-rows: repeat(4, 100px);")); |
|
main.append(addParagraph("In this example, all of the columns have the same width so we can specify them all with a single repeat function, but we can add others before or after and we could have more than one repeat function if necessary. Let's say that we want to have 4 columns with the first and last columns having a width of 300 pixels and the second and third columns having a width of 100 pixels. We can't use the repeat function for the 300 pixel columns because there are other columns between them, but we can use it for the 100 pixel columns and our grid-template-rows property would look like this.")); |
|
main.append(addSyntax("grid-template-rows: 300px repeat(2, 100px) 300px;")); |
|
main.append(addImageWithCaption("./images/grid5.jpg", "Demonstrating grid - using repeat to specify the width of some of the columns.")); |
|
main.append(addParagraph("So we can use the repeat function to replace two or more consecutive columns with the same width. Actually, you could use it to specify just one column width but you might find it easier to just specify the width for a single column or even the individual widths for 2 or 3. The only reason I can think of for using repeat for 1 or 2 columns is that if you know you are likely to change or even vary the number of columns, the repeat function makes it easier to change that.")); |
|
main.append(addParagraph("If you are specifying more than one width, you can use different units. For example, let's say we want to specify the first column with a percentage, say 35%.")); |
|
main.append(addImageWithCaption("./images/grid6.jpg", "Demonstrating grid - mixing units to specify the column widths.")); |
|
main.append(addParagraph("You would probably want your grid items to fill up the available space in the container and there are a couple of ways to do that. The first would be to use percentage values. For instance, if we have four columns and we want them all to be the same size, we might set the width of each to 25%.")); |
|
main.append(addSyntax("grid-template-rows: repeat(4, 25%);")); |
|
main.append(addImageWithCaption("./images/grid7.jpg", "Demonstrating grid - using percentages for column width so we can fill the available space.")); |
|
main.append(addParagraph("We haven't used margins to provide some space between the columns, but remember that we can put gutters between which we do with the gap property. Let's do that now with a value of 10 pixels.")); |
|
main.append(addSyntax("gap: 10px;")); |
|
main.append(addImageWithCaption("./images/grid8.jpg", "Demonstrating grid - adding gutters to space out the grid.")); |
|
main.append(addParagraph("There are a couple of things to note here. Firstly, the gap property applies to both the rows and columns. Secondly, the first row is now overflowing out of the container because the gaps are being added to the overall width of the elements in that row and since the grid items take up 100% of the width and the gutters add 30 pixels, the overall width is 30 pixels greater than 100% of the width of the container. We could use a percentage value for the gap, let's say 1% and reduce the column width to 24%.")); |
|
main.append(addImageWithCaption("./images/grid9.jpg", "Demonstrating grid - using a percentage value for gap.")); |
|
main.append(addParagraph("As you can see, there are a couple of problems with that. We now have a gap on the right-hand side. It's not a gutter but it happens to be the same size because we are now using 96% of the available width for the grid items and 3% for the gutters so that gap to the right is the remaining 1%. If we reduced the size of the grid items to 23%, you would see that this gap increase to 5%. Also, the gap between the rows is now much smaller because of the fact that 1% of the height is smaller than 1% of the width and since the row height is fixed at 100 pixels (which sets the height of the container to 200 pixels), the added 1% is causing a little bit of overflow.")); |
|
main.append(addParagraph("Using this kind of technique, you might end up with a layout that looks perfectly fine. The overflow may not be a problem if you don't use different background colours to highlight the difference between elements (which you probably won't do on a live site) and the gutters may not be a problem for similar reasons. However, there are some other problems with this approach which might become apparent as you develop a site. For one thing, it's a little bit of a 'suck it and see' approach where you are probably going to have to experiment with different values to find something that works well. This is because you don't really have too much control over the result unless you calculate the percentages required. In our example, we can remove the 1% gap by splitting that space between the four columns so these would have a width of 24.25%.")); |
|
main.append(addParagraph("This doesn't help with the gap between the columns where that approach will not work as we can see here.")); |
|
main.append(addImageWithCaption("./images/grid10.jpg", "Demonstrating grid - using a percentage value for the row height.")); |
|
main.append(addParagraph("What we are seeing here is a scenario where the columns are filling the space because we have used a width of 24.25% and a gap of 1%. We have also used a height of 50% for the rows and the result is that the height of the rows is determined by the content, not the percentage value (which is being ignored) and we still have the overflow at the bottom.")); |
|
main.append(addParagraph("Let's just take a second to consider why the percentage values are being ignored for row height, in case it isn't immediately obvious. When you look at a page in the browser, you are looking at essentially a two dimensional image with width and height. It's not unreasonable to see the width as being something that is governed by the width of the screen. It may not occupy the entire width because the browser might not occupy the full screen so it's more accurate to say that it is determined by the width of its container which is the browsers viewport.")); |
|
main.append(addParagraph("However, this is a fixed width. That might seem like a strange thing to say because you know that on a PC, you can change the size of the browser so it's clearly not fixed in the sense that it can't change. What I really mean is that whatever width the browser is at any given time will determine the space available to the elements in your page. It is fixed in the sense that it is fixed by the browser width.")); |
|
main.append(addParagraph("This is really just a long-winded way of saying that the horizontal space available to your page is limited and we can use percentage values to portion that space for each element (each column can be given 25% of the space, 24.24%, 100% or whatever percentage we want to give it).")); |
|
main.append(addParagraph("The height is, in a sense, similarly limited but websites were originally designed for displaying documents or textual information so there is an assumption that you will scroll vertically because the document you are viewing might not fit on one screen and so you will have to scroll down. This is perfectly reasonable. Scrolling down a page (or up) is something we are all accustomed to and it seems to be a normal part of viewing a web page. While its true that you may sometimes have had to scroll horizontally on a website, this seems far less natural and it would be ridiculously awkward and maybe even impossible to display a webpage if we didn't restrict one of the dimensions and if you have ever tried using notepad on windows to copy a large amount of text, you will see what I mean by that. Having to scroll to the right for every line in order to read it is a huge pain.")); |
|
main.append(addParagraph("What this means in practice is that how wide is the screen is an easy question to answer. How high is the screen (in terms of how much height is available to your rows) is much less straightforward unless you accept that the answer is simply as high as it needs to be.")); |
|
main.append(addParagraph("Take this page as an example. I am viewing it on a screen with a width of 1920 x 1080. The width of the document is therefore fixed at 1920 pixels or less. If we fixed the height at 1080 pixels and displayed all of the content, it would be way too small to read. So, the height is however much space is needed to contain the whole page and it would therefore be meaningless to try to calculate what 25% or 100% of that space would be.")); |
|
main.append(addParagraph("That's the long version. The short version - you can't express height as a percentage.")); |
|
main.append(addParagraph("Another disadvantage to this approach which will definitely become more apparent as the layout increases in complexity is that it is not really scalable. Let's say that you increase the number of columns from 4 to 8 or 12. You would then have to recalculate your percentages.")); |
|
main.append(addParagraph("What we really need is a method that allows us to specify the gap in pixels and then share the remaining space evenly (or unevenly) between the grid items and fortunately, grid provides that by giving is a new unit to specify the width with. The unit is fr and it calculates the space available to grid items and shares that space evenly. For example, if we go back to a gap of 10 pixels and we specify the width as 1 fr")); |
|
main.append(addSyntax("grid-template-rows: repeat(4, 1fr);")); |
|
main.append(addParagraph("the grid items now fill up the available space with gutters both between columns and rows of 10 pixels and no overflow.")); |
|
main.append(addImageWithCaption("./images/grid11.jpg", "Demonstrating grid - using the fr unit to share available space with the columns in the grid.")); |
|
main.append(addParagraph("We can also use fr to set different widths and these don't have to be whole numbers, you could use a value like 1.5 for example which you might want to do if you want a more fine-grained approach to setting the different widths. For now, let's say we want to go back to three columns and we want the first column to be twice as big as the other two. We could do that with")); |
|
main.append(addSyntax("grid-template-rows: 2fr repeat(2, 1fr);")); |
|
main.append(addImageWithCaption("./images/grid12.jpg", "Demonstrating grid - using the fr unit to share available space with the columns in the grid but with different widths.")); |
|
main.append(addParagraph("We could achieve a similar layout with flexbox, but grid allows us to be more explicit in the sense that the grid is defined by columns and rows rather than as a side effect such as by allowing items to wrap as we did with flex. The syntax is also a little bit neater than flexbox because it allows us to define the column and row sizes in the same property we use to declare them rather than having to add an additional property. As I mentioned before, both flexbox and grid are useful and can be combined, but if you want to define a grid, it is better to do that with grid rather than flexbox and stick to using flexbox when you want to align items within a container (which might be a grid item) along a single axis.")); |
|
main.append(addHeader("Columns, Rows and Gutters with Grid")); |
|
main.append(addParagraph("In the previous example, we used the gap property to set the gutter size for both rows and columns. There are also properties that allow us to set these individually and these are row-gap and column-gap. The gap property is a shorthand form that combines both of them. If we give gap a single value, that value sets the gutter size for rows and columns but if we give it two values, the first value sets the gutter size for the rows and the second sets the gutter size for the columns.")); |
|
main.append(addParagraph("It's worth noting that gaps were introduced with grid and this is reflected in the fact that the original names of the properties were grid-row-gap and grid-column-gap and the shorthand version was grid-gap. However, you can now also use this property with flexbox which is why grid was dropped from the name. As I write this, gap for flexbox is now supported by all major browsers.")); |
|
main.append(addParagraph("We can use any measurement unit for gap including percentage, pixels and fr. We can also set column and row sizes using the minmax function and this can be used with the repeat function. As an example, let's say we want two rows with a minimum height of 100 pixels but we also want to allow it to grow if there is more content. We can do that with")); |
|
main.append(addSyntax("grid-template-rows: repeat(2, minmax(100px, auto));;")); |
|
main.append(addParagraph("The MDN Web Docs list the different configurations you can use to create layouts with repeat which you can find <a href='https://developer.mozilla.org/en-US/docs/Web/CSS/repeat'>here</a>. We will experiment with the minmax function in the same <a href='https://codepen.io/Philip64/pen/zYMGqoZ'>codepen.io</a> example we used in the previous section. We can change the value for grid-template=rows so it uses the repeat function to set two rows with a minimum height of 100 pixels and we will set the maximum height to auto so this is the same as the above example. You won't see any difference because these elements don't really have any content and height has been set to the same value we already had. If we add some extra content so that the height of the column needs to be greater than 100 pixels, the auto setting for max will kick in and the height will grow to accommodate the content, as you can see here.")); |
|
main.append(addImageWithCaption("./images/grid13.jpg", "Adding content to a box in the second row causes the height of the box to increase in order to accommodate the content.")); |
|
main.append(addParagraph("Note that this uses Pirate Ipsum which was generated on the <a href='https://pirateipsum.me/'>Pirate Ipsum site</a> and is obviously the best kind of Ipsum!")); |
|
main.append(addParagraph("If we replace auto with 100px, that will set the maximum height at a fixed size so adding in the extra content doesn't cause the row height to grow and instead, we get the content overflwing as shown below.")); |
|
main.append(addImageWithCaption("./images/grid14.jpg", "Adding content to a box in the second row with a fixed height causes the content to overflow. The minmax value gives you a lot of flexibility by allowing you to set a minimum height to reduce the size of row or column when there is very little or no content and to increase the height when there is more content. As a result, it would be particularly useful when you don't know in advance exactly what the content will be. For example, you might have a box that a user can type text in to and it might be useful to be able to grow the box if the user types in a lot of text!")); |
|
main.append(addHeader("Positioning with Grid")); |
|
main.append(addParagraph("Once you have defined a grid, it is going to be useful to be able to position elements somewhere within that grid. To help you do that, the rows and columns are numbered starting from 1. As you might expect, the rows are numbered starting from the top with 1. The columns will be numbered from the left or the right depending on whether the language used on the website is a left to right language like English or a right to left language. This is shown in the image below which is taken from the course video.")); |
|
main.append(addImageWithCaption("./images/grid15.jpg", "Grid lines.")); |
|
main.append(addParagraph("You can also use a negative grid reference which counts from the end so for example, you might have three rows and 3 columns, both numbered 1 to 3 so the third row in the third column can be referenced with a three and a three. Essentially that means the third from the top and the third column. If we used negative references in this scenario, we are counting from the end (or bottom) so if we have negative one for the column and negative one for the row, that gives us the same grid reference.")); |
|
main.append(addParagraph("By default, items will appear in these 'cells' in the order in which they appear in the HTML, but we can change this using the following properties.")); |
|
main.append(addInsetBulletList(["grid-column-start", "grid-column-end", "grid-row-start", "grid-row-end"])); |
|
main.append(addParagraph("The shorthand version of these properties are")); |
|
main.append(addInsetBulletList(["grid-column", "grid-row-"])); |
|
main.append(addParagraph("These properties are a little different to the grid properties we have seen so far which are applied to the grid-container in order to define the grid. In order to position a specific item, we would apply the grid-column and grid-row columns to that item. As you may have realised, they perform two functions because in addition to defining where an item starts on the grid, they also define how many columns and/or rows that it spans.")); |
|
|
|
|
|
addSidebar("webdev"); |