This is a paragraph.
This is a paragraph with a link to my website in the line. I have also added some more text so that the content spans more than one line on a large screen such as my PC monitors which are quite large. The point of this is that this will result in the height of the box containing this element will be greater that that of the previous paragraph due to the fact that this one has a lot more content and that is one of the factors that will affect the height of the box. In simple terms, this is really just saying that if a paragraph has more lines, it will occupy more vertical space on the page which is what you would expect.
")); main.append(addParagraph("Footer<\p>")); main.append(addParagraph("You can see that the paragraphs now span the width of the main content panel so we would more accurately say that the width of an element is determined by the width of its containing element.")); main.append(addParagraph("One other point is that while we can set a width or height value for an element, for example we can set it to 50% so the element will only occupy half of the width of the containing element, this only has an effect if you apply it to a block element. Inline element ignore width and height properties and just take the width and height of the block element that contains them.")); main.append(addParagraph("Unlike a block element where the width, for example, might be much greater than the content as we saw with the header in our examples, an inline element just takes up whatever space it needs and essentially becomes a part of the block element so it doesn't make sense to try to set a width property for it.")); main.append(addHeader("The Display Property")); main.append(addParagraph("The display property is commonly used to change the way in which a page is laid out. For example, it is used to initiate both the Grid and Flexbox layouts which we will see in the next two chapters.")); main.append(addInsetList(["display: flex;", "display: grid;"])); main.append(addParagraph("In the context of layouts using float, it is used to change the way block and inline elements are displayed.")); main.append(addInsetList(["display: block;", "display: inline;", "display: inline-block;"])); main.append(addParagraph("In order to demonstrate this, I am going to follow the course video demo in codepen.io and this is our starting point.")); main.append(addImageWithCaption("./images/display1.jpg", "The starting point")); main.append(addParagraph("In the HTML, we have 4 elements. The first two are block elements and more specifically, they are divs. The other two are span elements and these are inline elements. We also have some CSS but initially, this is all commented out. If we uncomment all of the CSS, this will apply a green background to the divs and a lightgreen background to the span elements. It also sets a height of 100 pixels and a width of 200 pixels to both the div and span elements. This has the effect of changing the elements as shown below.")); main.append(addImageWithCaption("./images/display2.jpg", "Applying CSS rules for background colour, height and width.")); main.append(addParagraph("Notice that the block elements don't span the entire width of the container because of the width property we are applying to them. Also, recall that inline elements ignore height and width properties and so these don't change their size. Next, we will add a display property to span with a value of block.")); main.append(addImageWithCaption("images/display3.jpg", "Adding a display property to span with a value of block.")); main.append(addParagraph("Now, the span elements are being displayed as block elements so they are stacked vertically and the height and width properties have been applied. Next, we will add a display property to div and set this to inline.")); main.append(addImageWithCaption("./images/display4.jpg", "Adding a display property to div with a value of inline.")); main.append(addParagraph("The div elements are no longer stacked and the height and width properties are no longer being applied which is exactly what you would expect for inline elements. This property may sometimes be useful but only in quite rare circumstances so you won't commonly see it, if you see it at all. A more useful setting is inline-block and to see what effect this has, we will set it for both the div and span elements.")); main.append(addImageWithCaption("./images/display5.jpg", "Adding a display property to span and div with a value of inline-block.")); main.append("With the inline-block setting applied, the elements now display characteristics of both block and inline elements. They are not stacked (that's an inline element characteristic) but they do display with the width and height settings we applied (a block element characteristic). In terms of layout, this is a very useful setting and it is one that you will commonly see being used.") main.append(addParagraph("There are no margins between the elements but you may notice that there is a small gap between them and this is caused by the end of line character. This is something that happens with inline characters and you will see the same gap between the inline elements in the examples above. There are a couple of ways we can avoid that and the simplest is to put the elements on the same line or we can open a comment on one line after the element and close it on the next line before the element. The result is shown below.")); main.append(addImageWithCaption("./images/display6.jpg", "A couple of ways to eliminate the gap between inline elements.")); main.append(addParagraph("Both these methods work but they make the code look untidy and can be more difficult to read, so neither is recommended. A better method is to specify a margin (left in this case) with a small negative margin which will have the effect of moving the elements over slightly which can also remove that gap as shown below.")); main.append(addImageWithCaption("./images/display7.jpg", "A better way to eliminate the gap between inline elements.")); main.append(addParagraph("We specified a value of -4px for the left margin and as you can see, it has removed the gaps. Actually, the course video gives the impression that this figure is arbitrary, but you can experiment with the value and you will likely see that -4 is the exact value required. A value such as -3 will still leave a small gap. If we go the other way and set the value to -5, for instance, it can be a bit harder to see if this has exactly the same effect but if you set it to something like -10 or -20 it becomes much more noticeable that this results in the elements overlapping each other.")); main.append(addParagraph("The course video also notes that the padding property doesn't accept negative values and so cannot be used in the same way, but if you think about it, the reason why it doesn't accept negative values is also the reason why it wouldn't work anyway. Going back to our description of the box model, remember that padding is the space between the border (if there is one) or the edges of the element whereas the margin property refers to the space around the element. As such, only the margin property (of these two) can actually reposition the element. A negative padding value would effectively mean that the box is smaller than the content and so it makes perfect sense to not allow a negative value for it.")); main.append(addParagraph("Another method is to set the font-size for the container to 0 and we can see the result of doing that on its own below.")); main.append(addImageWithCaption("./images/display8.jpg", "Eliminating the gap between inline elements by setting the container's font-size to 0.")); main.append(addParagraph("This works because the space is a result of the fact that there is, in effect, a space character added by the end of line character so reducing its size to zero means that there is no gap. However, we can no longer see the text in the div and span elements because font-size is inheritable so when we set it to zero for the container, we are also setting the same value for the element within the container, in other words our div ad span elements. This means that we have to provide a CSS rule that will override this setting and the easiest way to do that is to add a font-size property to these elements as shown below where we set the font-size for both div and span to 16 pixels.")); main.append(addImageWithCaption("./images/display9.jpg", "Eliminating the gap between inline elements by setting the container's font-size to 0 and the font-size for div and span to 16 pixels.")); main.append(addParagraph("Removing the space between the elements might be something you do to make them look a little better, but there is another reason why we might want to do that. The four elements inside the container each has a width of 200 pixels. We haven't set a width for the container itself but if we do, it will need to be at least 800 pixels wide in order to accommodate all of the elements on the same line. In the image below, we have removed the font-size property from the container which effectively puts the gap between the elements back in place and the width for the container has been set to 800 pixels.")); main.append(addImageWithCaption("./images/display10.jpg", "Showing the effect that gaps between the elements can have on the overall width of several elements.")); main.append(addParagraph("As you can see, the fourth of our elements has wrapped around to the next line. This is because the total width of the elements is 800 pixels, the same as the width of the container. However, when you take the added space from the gaps into account, the total of the width of the 4 elements in that line is going to be slightly more than 800 pixels. If we set the font-size of the container back to 0 pixels, the total width of the 4 elements should now be exactly 800 pixels and so all 4 should fit into one line of the container. Side note, I am using the term line here in a way that is probably inappropriate or at least not entirely accurate but I think the meaning is clear enough. By line, I mean one row of elements so when I say that all four elements fit into a single line or wrap around to the next line, I mean simply that we have all of the elements aligned together horizontally or there is also some vertical stacking going on. In other words, the container is either wide enough to accommodate all four elements or it isn't.")); main.append(addImageWithCaption("./images/display11.jpg", "Getting four elements, each with a width of 200 pixels to fit neatly inside a container with a width of 800 pixels.")); main.append(addParagraph("Again, this is something that might be important for aesthetic reasons, but there is also a more important point. By removing the gaps, it makes it easier to calculate the width of the container so that it is just the right size to accommodate the elements we want it to contain in the way we want it to so we know in advance whether they will fit on one line. If there are gaps between the elements, we either need to know exactly what the width of the gaps is in order to take that into account when calculating what the total width of the container should be or we have to select some arbitrary value which is large enough to accommodate both widths of the elements and the gaps. I would suggest that if you want to keep the gaps between the elements, a better way to do that is to explicitly specify the width of the gaps by setting the width to a value of at least 4 pixels (bear in mind that you don't need to do that if you know the gap between elements is 4 pixels) or to some value, say 10 pixels, which gives you an overall effect that you think is appropriate or that just looks good. By doing that, you can then calculate the total width of the elements and the gaps and you can set the width of the container accordingly.")); main.append(addParagraph("In the past, display was often used as an alternative to floats since using the float property also introduces some problems and you can get more information on the differences between the two in an articles on designshack.net entitled What's the Deal With Display Inline-Block?'. This is largely a redundant point now since layouts are more commonly produced with the newer methods using grid and flexbox, but you may still find situations where these techniques can be useful.")); main.append(addHeader("The Box Model and Layouts")); main.append(addParagraph("We've already seen how different elements such as padding and margins affect the box model so just as a reminder, the size of the box that contains an element is given by the height and the width and also the padding and border sizes. Understanding this is not so important when elements are following the normal flow, but when you want to create a layout where elements are placed side by side, it becomes more important. Knowing how much space an element takes up is important in working out whether they will fit together.")); main.append(addParagraph("Let's look at an example on copdepen.io. We have a div with no text content, we are really only interested in its size so it has a light blue background so we can see that and it's width and height have both been set to 200 pixels and you can see what this looks like below.")); main.append(addImageWithCaption("./images/box_model1.jpg", "A HTML element with width and height set to 200 pixels and with a light blue background to make it easier to see.")); main.append(addParagraph("We want to add some CSS rules in order to show how this impacts both the size of the element and the amount of space it takes up. We will start that off by adding padding to the div and we should see this increasing in size and we can see that below.")); main.append(addImageWithCaption("./images/box_model2.jpg", "How padding affects the size of an element.")); main.append(addParagraph("We added padding of 40 pixels with this rule")); main.append(addSyntax("padding: 40px;")); main.append(addParagraph("so that is adding 40 pixels on each of the four sides and has the effect of increasing both the width and height by 80 pixels so the size of the element is now 280 pixels by 280 pixels. This is quite a big difference in size and I think this is obvious in the screenshots above.")); main.append(addParagraph("Next, we will add a border with a width of 20 pixels so again, this is being applied on all sides and increases the width and height by 40 pixels giving us a total element size of 320 pixels by 320 pixels.")); main.append(addImageWithCaption("./images/box_model2.jpg", "How border affects the size of an element.")); main.append(addParagraph("The difference isn't as obvious now but if you try the exercise in codepen, it makes it a lot easier to see the changes because they happen in the viewing panel as soon as you make the change in the CSS.")); main.append(addParagraph("Lastly, we will add on a margin of 40 pixels.")); main.append(addImageWithCaption("./images/box_model2.jpg", "How margin affects the size of an element.")); main.append(addParagraph("So the margin, as we mentioned before, has not increase the size of the element, but it increases the amount of space that it occupies and you can see that in terms of the gap between the top of the viewport and the left hand side. The margin is on all four sides but we can't see it to the right and below because there are no other elements but if there was another element to its right and below, it is possible that we see these being shifted when we introduce our margin. I say possible because they might not be shifted if there is already a margin there due to margin-collapsing so we are really only going to see an effect if the margin we set is larger than an existing margin. For example, if we had a similar div below it which already had a margin set to 50 pixels, setting the margin to 40 pixels would have no effect in terms of the space between the two. On the other hand, if we set the margin to anything greater than 50, let's say 60 pixels, we would then see an increase in the space between the elements but we would only see it increase by 10 pixels.")); main.append(addParagraph("It may be difficult to appreciate how important it is to properly understand how these factors, particularly margin can affect not only how much space an element needs but also how it affect the alignment of other elements but you will see how this can have an affect if you are building a layout where you want elements to sit alongside each other across the page. However, it is also important to remember that what we have described here is the default behaviour and this can be overridden with the box-sizing property.")); main.append(addParagraph("The box-sizing property has two possible values, the first of which is content-box and to explain this, let's assume that you are applying the property to an element where we have already set a width and height of 200 pixels and we have no padding, borders or margins. In essence, that means that there is an area that is 200 by 200 pixels for our content. If we add padding of 10 pixels all round and a border with a width of 10 pixels, the amount of space available for content is still the same 200 by 200 pixels which means that the overall size of the element is increased to 240 by 240 pixels. That is, we add 20 pixels to the top, 10 for the padding and 10 for the border and this also applies to the bottom as well as the left and right sides. So that gives us")); main.append(addSyntax("height = 200 pixels + 10 pixels top padding and 10 pixels + 10 pixels top border and 10 pixels bottom border = 240 pixels.")); main.append(addSyntax("width = 200 pixels + 10 pixels top padding and 10 pixels + 10 pixels top border and 10 pixels bottom border = 240 pixels.")); main.append(addParagraph("This might be a little bit clearer if we look at the layout in the browser developer tools for our example on codepen.io.")); main.append(addImageWithCaption("./images/box_sizing.jpg", "How the box-sizing property affect the overall size of an element when it has the value content-box.")); main.append(addParagraph("In this example, we have set the box-sizing property to content-box although this is exactly the same result that we would see if we omitted the property. So, this is the default behaviour and you can see that the height and width are both 200 pixels with values of 10 pixels for both padding and the border width is 10 pixels and the overall width shows as 240x240.")); main.append(addParagraph("The other value we can give for the box-sizing property is border-box. This can make it easier to work out how elements will interact with each other. In our example, if we give box-sizing a value of border-box, the size of the element will be 200x200 pixels regardless of what value we set for padding and border-width.")); main.append(addParagraph("If we start with an element with a height and width of 200 pixels and we then add the same 10 pixels for padding and border-width, the area available for content is reduced accordingly. Again, a visual representation of this might be helpful.")); main.append(addImageWithCaption("./images/box_sizing1.jpg", "How the box-sizing property affect the overall size of an element when it has the value border-box.")); main.append(addParagraph("This is identical to the previous example, but this time we are specifying box-sizing rather than either specifying content-box or accepting the default. We can see that we still have 10 pixels of padding and a border width of 10 pixels. Rather than this being added to the overall size of the element, the size remains the same and the content-area reduces to accommodate these values so in effect, we are subtracting 40 pixels from both the width and height to give us the size of the content area but the overall size is still 200x200 pixels.")); main.append(addParagraph("Note that the box-sizing property was applied to our HTML element directly using the elements class as a selector. If you want to set this for the whole site, it is generally recommended that you apply it at the start of your CSS file (on a file that is linked to all of the site's HTML documents). If you have more than one CSS file and you don't have a file that you use site-wide, you would have to apply this to a CSS file for each of your pages. You don't have to put it in a different file for each HTML document, but each document must be linked to one CSS file that has these rules. You would normally attach it to the HTML element like this.")); main.append(addInsetCodeListing(["html {", " box-sizing: border-box;", "}", "", "*, *:before, *:after {", " box-sizing: inherit;", "}"])); main.append(addParagraph("This is doing a couple of things. Firstly, by setting the property for HTML which is at the top of the DOM, this essentially makes it available to any HTML element and the box-sizing: inherit rule ensures that those HTML elements do actually inherit this setting. This is quite an important topic in CSS and is known as the Box Model fix. You can read more about in on paulirish.com and for reference, see the page on MDN Web Docs under box-sizing. If you do (and personally I think you should) have a CSS stylesheet for any styles you want to apply on a site-wide basis, adding this code-snippet at the top of that stylesheet will ensure that all HTML elements have box-sizing set to border-box so any width and height values you apply to an element will not change if you add either padding or a border (or even both) unless you override that with a more specific rule.")); main.append(addParagraph("Essentially, this means that you have flipped the default behaviour from content-box to border-box meaning that if you want the content area for an element to stay the same regardless of whatever values you add for padding and border, you have to explicitly set the value of box-sizing to content-box.")); main.append(addParagraph("Of course, regardless of whether you use content-box or border-box to size your elements, anything you set for margin will still increase the space that an element takes up on your page because as we saw earlier, it does not affect the overall size of the box. It also gives you the option to set a value of auto for left and right and if you do that, it has the effect of centering an element on the page and if you have more than one element aligned horizontally, it will centre those elements as a group. Essentially, it calculates the margin setting required to produce that effect and applies it so the developer doesn't have to calculate what margins are required for that. Going back to our codepen example, recall that we had specified a margin of 40 pixels on either side.")); main.append(addParagraph("Let's change that setting to")); main.append(addSyntax("margin: 40px auto;")); main.append(addParagraph("You might recall that giving margin 2 values like this has the effect of applying the first value to the top and bottom margins and the second to the right and left margins so this is the equivalent of")); main.append(addSyntax("margin: 40px auto 40px auto;")); main.append(addParagraph("The result is shown below")); main.append(addImageWithCaption("./images/auto_margin.jpg", "How setting the value of margin-left and margin-right to auto affects the horizontal placement of an element.")); main.append(addParagraph("As you can see, the size of the element hasn't changed. Since we have set this to use border-box as the setting for border-sizing, the size is 200x200 pixels and this is because we set both the height and width to 200 pixels and you can see that, as before, the size of the content area has reduced to 160x160 pixels.")); main.append(addParagraph("The margin at the top is clearly visible and this is our 40 pixels setting, but the margins to the left and right have been automatically set to 393 pixels centering the element. If you resize the window, these values will change to keep the element centred.")); main.append(addParagraph("If we remove the value for width, the left and right margins will disappear because this is a block element so it will fill the width of its container. If you don't have a specific width, how would the browser know how much space to add to the left and right margins since any value would centre the element as long as it was the same on both sides? However, let's look at how the auto margin works. The container that our element is in has a width which we'll call x which is, in this, example, the same as the width of the viewport Let's assume for illustration purposes that this is 1000 pixels. Within that container, our box element has a width of 200 pixels so if we subtract 200 from 1000, we get 800 pixels and this is the amount of space unoccupied by the element. This means that it is also the total value of the left and right margins.")); main.append(addParagraph("If we don't set any value for the left and right margins or to be even more explicit, we set the left margin to zero pixels, the right margin will have a value of 800 pixels. When we set the value of the margins to 40 pixels, the left margin has that value but the right margin has a value of 760 pixels. Strictly speaking, the right margin has a value of 40 pixels, but since there is nothing else on the same line, there will be a space between that and the right edge of the container of 720 pixels so you will see this as effectively a margin of 760 pixels.")); main.append(addParagraph("If we set the left and right margins to auto, the browser knows that the width of the container is 1000 pixels and if you subtract the width of the element, that leaves 800 pixels so that gives us left and right margins of 400 pixels.")); main.append(addParagraph("If you don't specify any width for the element, it will have a width of 1000 pixels which gives us left and right margins of 0 pixels.")); main.append(addHeader("The float Property")); main.append(addParagraph("Although floats are not designed for the purpose of creating layouts, they have been used for that purpose in the past. This was largely because of a lack of a better option but we now have flexbox and grid, so you won't see float layouts so much now. Essentially, floats were created to allow text to wrap around images and was designed as a method of replicating print layouts because many early websites were online versions of magazines, newsletters and other forms of print media.")); main.append(addParagraph("The float property has four possible values.")); main.append(addInsetBulletList(["None (the default value)", "Left", "Right", "Inherit (from the parent element)"])); main.append(addParagraph("We will use codepen.io to explore floats and our starting point is shown below.")); main.append(addImageWithCaption("./images/float.jpg", "Exploring the float property on codepen.io - starting point.")); main.append(addParagraph("The HTML is basically two divs with the class wrapper. The first of these has an image and a couple of paragraphs while the second has just a couple of paragraphs. We want the image to appear on the left (which it is at the moment) but we want the text to wrap around it. To do that, we will set the float property for the image to left. This gives us the desired effect.")); main.append(addImageWithCaption("./images/float1.jpg", "The image now has a float property set to left.")); main.append(addParagraph("One of the effects of the float property if it is set to left or right (or inherits a value of left or right) is that it takes the element out of the normal flow so it doesn't stack with other elements vertically. In the first image, because there was no float value, the image was first on the page with the first wrapper below it and the second below that. When it is removed from the normal flow, the next element is placed, in this case, at the top of the screen with the next following on after it. This is important to understand because it explains why the second div is also wrapped around the image.")); main.append(addParagraph("We can't really see it here, but the two wrapper divs do span the entire width of the container, it is only the content that is moving to take account of the fact that there is a floated image there. If we set a border and a margin for the wrapper div, the effect will be a little but easier to see. We will also add a background colour to the paragraphs which will show us that they are also spanning the width of their container (which is the wrapper div). We will also add a margin around the image.")); main.append(addImageWithCaption("./images/float2.jpg", "Adding some CSS so we can see how the elements are arranged in relation to the image.")); main.append(addParagraph("So this clearly shows that the wrapper divs do span the entire width of their container as do the paragraphs. We can also see that the wrapper divs are stacked vertically starting from the top of the page and the paragraphs are also stacked vertically within the divs. The paragraphs are partially hidden by the image but the content has been shifted, where necessary, so that it is still completely visible. As we saw before adding this CSS, the paragraphs look as though they start at the right edge of the image so although they haven't been moved, since the content is shifted, the effect is the same.")); main.append(addParagraph("One additional point to make is that the image is inside the first wrapper and this might suggest that the second div shouldn't start until the end of the first div and therefore its paragraphs shouldn't wrap around the image like the paragraphs in the first image do. In fact, it doesn't start until after the end of the first div, but as you can see from the outline of the wrappers we get with border, the wrapper no longer encapsulates the image. In HTML terms, the image is inside the div, but in terms of the flow of the document (in other words, how the browser displays it, is displayed separately from the div and this is a consequence of it being removed from the normal flow and that's why the text from the second div will also wrap around it. In many cases, you will want only the text in the same div to wrap around it. If we clear the float so that the second div is not being affected by it, by which I mean that it is no longer going to move its content to accommodate the image, that would produce the desired effect and we will look at that next.")); main.append(addParagraph("We will use the same page on codepen.io so don't close it just yet!")); main.append(addHeader("Clearing floats")); main.append(addParagraph("As we saw in the previous section, when we float an element, this removes it from the normal flow and so the elements that follow it, assuming they are part of that normal flow, will wrap around the floated element. In the previous example, where we demonstrated the float property, you may have noticed a CSS rule for the class, clear. Our HTML doesn't have an element with that class but we can apply the rule to an element simply by adding the class name. We do it that way so that we can more clearly see how this works.")); main.append(addParagraph("If we add that class to the first wrapper, it has no effect and I would assume that this is because the image is inside that element so it can't really clear it as such. However, if we add the clear to the second paragraph in this wrapper, that paragraph will nl longer wrap around the image.")); main.append(addImageWithCaption("./images/clear.jpg", "The effect of adding a clear property to the second paragraph in the first wrapper.")); main.append(addParagraph("Adding the class to the second wrapper does make a difference as you can see here.")); main.append(addImageWithCaption("./images/clear1.jpg", "The effect of adding a clear property to the second wrapper.")); main.append(addParagraph("Clearly, the first wrapper is still positioned behind the image with its content flowing around. However, the second wrapper appears below the image so its content is no longer being wrapped around the floated element.")); main.append(addParagraph("If we remove the second element and we don't have a float property applied to the remaining wrapper or any of its elements, this can cause a problem. Since we no longer have a clear property, we will likely need to remember about the float when adding additional elements to the page. The solution is to add the clear property to the container. This is known as self-clearing and there are three ways to do that. The first of these is the clearfix hack in which we add this CSS to an element.")); main.append(addInsetCodeListing([".clearfix:after {", " content: ?\"\";"," display: table;", " clear: both;", "}"])); main.append(addParagraph("This is adding a space after the element and applying a clear to it. It should be added to the parent of the floated element and the class name, clearfix, is used because that was the name used in the original hack. As it is just a class name, you can call it something else if you like but the name makes it pretty clear what the CSS is doing here, particularly to someone who is familiar with CSS. You can read more about this on the CSS Tricks page, Clearfix: A Lesson in Web Development Evolution by Jay Hoffmann (3rd July 2018).")); main.append(addParagraph("To test this and confirm how it works in practice, I have amended the HTML and CSS in the codepen.io example so we now have our first wrapper div and a second div with the class other_wrapper. I have also added the clearfix hack to the CSS and the class selector is clearfix so I can apply it to any element by adding that class name. In the first example, I have added this to the second element - note that if you read the description of the hack above, you will probably know this won't work.")); main.append(addImageWithCaption("./images/clearfix.jpg", "The effect of applying the clearfix hack to other_wrapper.")); main.append(addParagraph("The earlier description mentioned that the fix should be applied to the parent of the floated element which is the first wrapper, so let's apply it there.")); main.append(addImageWithCaption("./images/clearfix1.jpg", "The effect of applying the clearfix hack to wrapper.")); main.append(addParagraph("As you can see, this provides the effect we were looking for now so now any elements added after wrapper will not be affected by the float property on the image. This allows us to ensure that only the text that we want to wrap around the image will do that so it gives a little more control over how the elements appear and this is true even for elements we plan to add later.")); main.append(addParagraph("Another option is to set an overflow property on the parent of the floated element which as you can see below, has the same effect.")); main.append(addImageWithCaption("./images/overflow.jpg", "The effect of applying the overflow property to wrapper.")); main.append(addParagraph("This is not what the overflow property is for but it does have the desired effect in terms of clearing floats but you may want to run into problems if you want to use the property for its actual purpose in the same element.")); main.append(addParagraph("The modern way to do clear floats is using the display property with a value of flow-root. At the time the video was recorded, this was still in the draft-phase but if you check it out on caniuse.com, you will see that this is now a Candidate Recommendation as of early May 2023 and browser coverage is now pretty goof as long as you are not using IE. Again, this is added to the parent of the floated element.")); main.append(addImageWithCaption("./images/flow-root.jpg", "The effect of applying the display property to wrapper with a value of flow-root.")); main.append(addHeader("Setting Up Your Project")); main.append(addParagraph("During the course, we are going to produce one layout as a project but we will create in three different ways, first with float, then with flexbox and finally with grid so this should give you some idea of the differences between the three approaches to creating a layout.")); main.append(addParagraph("Let's start by taking a look at the basic project without any CSS being applied to create the layout.")); main.append(addParagraph("It doesn't look particularly impressive at this stage but you can see the different elements of the page starting with a header, a section for our main content, a section for navigation, a sidebar and a footer. The HTML file can be found in the exercise files in any of the chapter folders. At this point, the CSS is really just there to show you what the different sections are. We have copies of the starting CSS for each of the three versions of the project in the start folder and in the chapter folders, you will find the completed CSS.")); main.append(addParagraph("The names of the elements have been carefully chosen and give some indication of where they will appear in the layout. The header will be at the top and will span the page as will the footer which will be at the bottom. Below the header, we will have the navigation bar to the left, the sidebar will go to the right and the main content are will be in the middle.")); main.append(addParagraph("You might notice that the order in which the elements appear in the normal flow has the main content immediately after the header and before the navigation bar. It's actually pretty common to have these reversed. The navigation is often just below the header at the top of the page and in our layout, it is the first element in the central area so for a lot of reasons, it makes sense to put it right after the header. The reason we didn't in this case is for accessibility purposes. If a someone is using a screen-reader on the page, it will read the main content before whatever is in the navigation bar so it makes it a little easier for the reader to get to the main content.")); main.append(addParagraph("You can get more info on accessibility in general from webaim.org and you can read an article specifically relating to the placement of the navigation bar or links in an article entitled Skip Navigation Links. This also provides a technique which will allow users with a screen reader to skip the navigation links as we will see below.")); main.append(addHeader("Exercise: Build a Layout with float")); main.append(addParagraph("We will have to start by back-tracking a little here because with float, there is no way to reorder the elements so that we have the navigation appearing before the main content in the central panel so we are going to have to amend the HTML to put the navigation panel after the header. We will also add in this link as the first item in the navigation panel.")); main.append(addSyntax("<a href=\"#main-content\">skip navigation</a>")); main.append(addParagraph("That link will take you past the navigation and straight to the main-content which is what most users would be interested in.")); main.append(addParagraph("At this point, we can start thinking about the CSS and we are going to use a mobile-first approach to this, we will use the developer tools and reduce the size of the view port to the point where it is small enough to want to use a single column layout which is our starting point. We can then increase the width until the point where it looks like two columns could be supported and that seems to be the case at around 600 pixels.")); main.append(addImageWithCaption("./images/browser-developer-tools.jpg", "The viewport at around 600 pixels width where it looks like a two column layout might work.")); main.append(addParagraph("We will use a media query set with a minimum width of 600 pixels so that will start with")); main.append(addSyntax("@media (min-width: 600px) {")); main.append(addParagraph("We are aiming to have the navigation bar to the left with the main content beside it to the right but we want the main content to have most of the available space so we can set the width of the navigation panel to 25%")); main.append(addInsetList([".nav {", " width: 25%", "}"])); main.append(addParagraph("and we can use a similar rule to set the width of the main content panel to 75%.")); main.append(addInsetList([".main {", " width: 75%", "}"])); main.append(addImageWithCaption("./images/browser-developer-tools11.jpg", "Reduced sizes for the nav and main elements.")); main.append(addParagraph("The sizes look fine there, but we still have everything stacked according to the normal flow so next, we want to apply the float property to the nav and main elements. For nav, this will be left but for main, which is going to occupy the remaining space next to the navigation panel, it doesn't really matter so we will just use the same value and float left.")); main.append(addImageWithCaption("./images/browser-developer-tools2.jpg", "Adding a float property (left) to the nav and main elements.")); main.append(addParagraph("We can now see that the panels are displayed in a partial 2-column layout but notice that the main content panel is also wrapping around the next element, the sidebar because we didn't clear the float so we will add that in now.")); main.append(addInsetList(["aside {", " clear: both;", "}"])); main.append(addImageWithCaption("./images/browser-developer-tools3.jpg", "Applying a clear property to the aside element.")); main.append(addParagraph("Notice that the nav column is not as tall as the main column which gives us an unattractive look but we are going to ignore that for several reasons. Firstly, we can only see that because of the background colours and those are only being used to show us exactly where the elements are in relation to each other. Secondly, more modern methods of creating a layout would automatically fix this so its a technique that we probably won't need to use or learn.")); main.append(addParagraph("We are now ready to start resizing the viewport again to look for the point where we can switch to a three column layout and that seems to happen at around 900 pixels.")); main.append(addImageWithCaption("./images/browser-developer-tools4.jpg", "The viewport at around 900 pixels width where it looks like a three column layout might work.")); main.append(addParagraph("We will round this down to 850 so our media query will start with")); main.append(addSyntax("@media (min-width: 600px) {")); main.append(addParagraph("We will keep the width of the nav panel at 25% and reduce the main panel to 50% which gives us enough room to set the width of the aside panel to 25%.")); main.append(addImageWithCaption("./images/browser-developer-tools5.jpg", "Resizing the main panel and the sidebar.")); main.append(addParagraph("The sidebar is still shown below the main panel because of the clear property so let's set that to none and we will also add a float property with a value of right.")); main.append(addImageWithCaption("./images/browser-developer-tools6.jpg", "Changing the clear on aside to none and floating it to the right.")); main.append(addParagraph("This gives us the three column layout we wanted but footer looks like it is being floated too. This is because we don't have a clear property now. Note that we wouldn't really need it if the height of the nav bar and sidebar matched the height of the main panel!")); main.append(addImageWithCaption("./images/browser-developer-tools7.jpg", "Applying the clear to the footer.")); main.append(addParagraph("We now have our three column layout but we still have one issue and that is when viewed on a very large screen, say with a width of more than 100 pixels, the content seems to be spaced out a bit too much.")); main.append(addImageWithCaption("./images/browser-developer-tools8.jpg", "The layout on a larger screen.")); main.append(addParagraph("To see the layout at its maximum size, I have closed off the browser developer tools. We want to make a change so that everything is more central when the screen width is over a set size and we will use 1000 pixels for that. However, we won't use a media query for that. We will make use of the fact that all of the elements that make up the layout are contained with in a div element that has the class, container. Since the layout is displayed inside this container, we can set a maximum width of 1000 pixels on it and use margins to centre the content like this.")); main.append(addInsetList([".container {", " max-width: 1000px;", " margin: 0 auto;", "}"])); main.append(addParagraph("This doesn't affect the layout on smaller screens because it's a maximum width so the content will always span the entire width of its container if the width is 1000 pixels or less so it only has any effect when the screen width is greater than that.")); main.append(addImageWithCaption("./images/browser-developer-tools9.jpg", "The layout on a larger screen with better spacing.")); main.append(addParagraph("Using a maximum width and using percentage values for the width of the floated elements gives us much more flexibility with the layout and allows it to act in a responsive way without needing to use media queries. In my (admittedly limited) experience, modern layout techniques are often pretty responsive anyway so for the layouts I've designed so far, I have usually found that I can get a fairly responsive result without adding media queries so I tend to add those on later to tweak the layouts on smaller screens.")); main.append(addHeader("Position: Relative and Absolute")); main.append(addParagraph("With the position property, we can define how an element is position in relation to its current position, its containing element or the viewport and it is very useful for fine-tuning a layout but not for creating a full layout. To demonstrate this, we will use another example on codepen.io. To begin with, this is a pretty basic HTML page with elements given background colours to make them easier to distinguish.")); main.append(addParagraph("Note that all of the elements are following the normal flow so we have the header, navigation bar, main content and footer. Inside the main content panel we have some paragraphs and a couple of divs creating the rectangles we can see and these elements are following the normal flow within the containing element (which is main content). As a kind of visual aid to what's going on, these have been labelled as the absolute box and the relative box.")); main.append(addImageWithCaption("./images/position.jpg", "The layout we will use to demonstrate the position property.")); main.append(addParagraph("If we go ahead and add the position property with a value of relative to the relative box, we won't see an immediate change because this will position it relative to its current position (or you might think of this as relative to where it would be if we didn't add a position property) but relative is the only position value that does not remove the element from the normal flow. As a result, the element is sitting relative to where it would be anyway, so we need to specify where it should be positioned relative to that.")); main.append(addParagraph("If we give it left and bottom properties with values respectively of 50 and 20, we will then see it move to a position that is relative to the containing element and this is 50 pixels away from the left edge and 20 pixels away from the bottom. Note that we can also specify top and right properties.")); main.append(addImageWithCaption("./images/position1.jpg", "Applying position with a value of relative to the relative box.")); main.append(addParagraph("In a sense, a relative position is similar to the float property but in the case of position, other content doesn't flow around the positioned element so you can get a situation as we can see above where an element (the absolute box) is partially hidden by the positioned element.")); main.append(addParagraph("This hints at a property we haven't encountered yet which is the z index. We tend to think of a web page as being 2 dimensional in that the page and various elements have width and height properties. We might think of this as being the x and y axis but there is also a z axis and this applies here where we have two elements partially occupying the same space. These elements are layered on top of each other according to the z-index property. Essentially, where there is an overlap, the element with the higher z index value will appear to be on top.")); main.append(addParagraph("You might have noticed that we haven't applied this property so both of these elements have the default value for z index which is zero. Since they both have the same value, the order in which they are layered is determined by the order in which they appear in the flow which makes sense because you would expect the browser to put the absolute box on the screen first followed by the relative box so you should expect the relative box to be on top.")); main.append(addParagraph("Let's go ahead and set the position property to absolute for the absolute box. As with relative, we don't really see it's position change relative to the containing element, but we do see a change in where the relative box is positioned. Remember that for position, relative is the only value that doesn't remove the element from the normal flow. In this case, we have used the value, absolute, so this does remove absolute box from the normal flow.")); main.append(addImageWithCaption("./images/position2.jpg", "Applying position with a value of absolute to the absolute box.")); main.append(addParagraph("The result is that the relative box now positions itself just below the last paragraph in the main box. Note, however, that it is still appearing after the absolute box in the HTML so it is shown as being on top. If we give absolute box a z index of 1 (actually, any number greater than zero would have the same effect), the absolute box now appears on top.")); main.append(addImageWithCaption("./images/position3.jpg", "The absolute box has a z index of 1 and so is on top of the relative box.")); main.append(addParagraph("We can position the absolute box in the same way as we did the relative box and in this case we will specify 20 pixels for top and 20 pixels for right. With an absolute value for position, the element is positioned relative to the nearest ancestor with a position property. If there isn't one, it is positioned relative to the viewport.")); main.append(addImageWithCaption("./images/position4.jpg", "The absolute box positioned relative to the viewport.")); main.append(addParagraph("You will see that if you resize the browser, the absolute box will stay in the top right corner rather than disappearing. If we want it to be positioned relative to the main content panel, we can apply a position value to main content. We could give it any value but relative is usually the best option because we don't want to remove main content from the normal flow.")); main.append(addImageWithCaption("./images/position5.jpg", "The absolute box positioned relative to main content.")); main.append(addParagraph("In the next section, we will look at the remaining 3 possible values for the position property so we will use the same codepen.io page for that.")); main.append(addHeader("Position: fixed, sticky and static")); main.append(addParagraph("With a navigation bar, you will often see it at the top of a page and when you scroll, it remains in place. This makes it easier for a user to navigate around the page, especially if you have a lot of content that the user has to scroll to view, because they won't have to scroll all the way back to the top of the page in order to access it. Essentially, we want its position to be fixed so we can apply a position property with the value fixed to our nav bar. We will also set the top property to zero so it will be right at the top of the page. It might be worth pausing to consider what effect this will have, bearing in mind the fact that this is going to take the nav bar out of the normal flow. The result is shown below.")); main.append(addImageWithCaption("./images/fixed.jpg", "We applied a fixed position property to the navigation bar and this is the result.")); main.append(addParagraph("You may or may not have expected that! Since the nav bar has been removed from the normal flow, it is now sitting behind the main content window since that element comes after it on the HTML and they both have the default z index. If we add a z index of 100, we just want to give it some high value so it is less likely it will conflict with something that has a higher index, we will now see it appear over part of the main content. We also want to tweak the CSS a bit here, so we will give it a width of 100% so it spans the width of the container and we will give it a top value of 0 so it appears right at the top.")); main.append(addImageWithCaption("./images/fixed1.jpg", "Moving the nav bar to the top of the page.")); main.append(addParagraph("You might need to resize the screen to check this but the nav bar is fixed at the top of the page and it stays there even when scrolling down the page. However, this is now occupying the same space as the header. We can't fix it with the z index value now because we want to be able to see both so we will add some space at the top of the page, above header for the nav bar to sit in. Essentially, we are applying a top margin which is the same size as the height of the nav bar so that the header (and everything that follows it) is shifted down by the precise amount we need to accommodate the nav bar. We can check that with the layout in the browser developer tools which shows that the height of the content in nav bar is 23 pixels. We have an additional 20 pixels of padding on the top and also the bottom so that gives us a total of 63 pixels. We will make that an even 64 pixels.")); main.append(addImageWithCaption("./images/fixed2.jpg", "Moving the header to make room for the nav bar.")); main.append(addParagraph("The course mentions that the sticky value is still in the experimental stage but again that's out of date info. It is now at the working draft stage with more or less complete browser coverage. It's kind of a cross between relative and fixed in that if you apply it to an element, that element will sit in a fixed position relative to the container which means that it will move when you scroll but when it reaches its specified offset, it becomes fixed in position. Let's change the value for nav bar's position property to sticky.")); main.append(addImageWithCaption("./images/sticky1.jpg", "Applying sticky to the nav bar.")); main.append(addParagraph("It is now in a relative position so we can see it between the header and the main content and we can remove the margin from above the header.")); main.append(addImageWithCaption("./images/sticky2.jpg", "We removed the margin at the top.")); main.append(addParagraph("The nav bar still has a top value of zero, so when we scroll down, the nav bar becomes fixed when it reaches the top of the page.")); main.append(addImageWithCaption("./images/sticky3.jpg", "The nav bar reverting to a fixed position.")); main.append(addParagraph("The sticky value might be useful if you have an element you want to show in context with a relative position but where you also want it to remain visible even if the user scrolls.")); main.append(addParagraph("The final value is static and this is the default value. If an element has a position value of static, it will just be displayed in the normal flow. Since it is the default value, you won't normally have to specify it. One possible exception would be where you need to override another value. For example, let's say that we want the absolute box to revert to a static position if the screen size is 600 pixels or less in width. We can add a media query with a max-width of 600px to set the position to static.")); main.append(addImageWithCaption("./images/static1.jpg", "The width of the viewport here is just over 600 pixels.....")); main.append(addImageWithCaption("./images/static1.jpg", ".....and here it is just less than 600 pixels.")); main.append(addParagraph("As you can see, the absolute box sits in its absolute position when the screen width is large enough but as soon as it gets to 600 pixels or less, it reverts to a static position.")); main.append(addParagraph("There can be a temptation to use position to do a complete page layout but if you are doing that, particularly if you are using large offsets to get an element just where you want it, you would be better off switching to a better layout method. Like float itself, the position property is best used to fine tune the positioning of components and best used to position element inside a container rather than (for the most part) positioning elements on the page.")); main.append(addParagraph("The techniques we have looked at so far can be used to create layouts, but are generally better suited to fine tuning individual elements of a layout. Next, we will start looking at the techniques which are better suited to creating complete layouts.")); addSidebar("webdev");