An old-timey web dev tutorial (and a friendly intro to CSS layouts)
Over the last few chapters, we’ve learned how to manipulate the size of boxes and the space around them, but for the most part, we were stuck with the default vertical flow of the page. Block elements always appeared vertically one after another, effectively limiting us to a single-column layout.
“Floats” let you put block-level elements side-by-side instead of on top of each other. This is a big deal. It lets us build all sorts of layouts, including sidebars, multi-column pages, grids, and magazine-style articles with text flowing around an image. This is where we finally start creating real web pages.
Float-based layouts have mostly been replaced with Flexbox in modern websites. But, that’s not to say this chapter isn’t worth reading. For over a decade, floats served as the foundation for the majority of websites on the Internet, which means you’ll definitely encounter them at some point in your career.
Perhaps more importantly, the limited nature of floats makes them a gentler introduction to CSS layouts than Flexbox. Instead of being overwhelmed with all the possibilities of Flexbox, we’ll get a chance to focus more on the process of building up a sophisticated web page layout.
This chapter demonstrates CSS floats with a pretty simple sample project. Instead of working with proper HTML content as we have been in previous chapters, we’ll be styling a bunch of empty <div> elements. We’ll end up with something that looks like the following, which is a pretty big divergence from the types of web pages we’ve been creating thus far.
First, create a new folder called floats, then add a new web page called floats.html with the following markup:
This gives us the basic structure for most websites on the Internet. We have a place to put a navigation menu, a sidebar, the main content of the page, and a footer. Think of all these as container divs that you can put your actual HTML content into.
You won’t see much when you open floats.html in a browser because empty elements have zero height. We’ll fix this in the next section.
Floats alter the default layout of a web page, so we should probably start by reviewing what exactly that “default” behavior is. We introduced this in block elements versus inline elements, but it’s about to become much more important.
We can get a better look at our example page by adding some background colors and explicit heights to each of our <div> elements. Add this to styles.css:
This gives us a nice rainbow, which isn’t what we’re looking for, though it does demonstrate some useful concepts.
The important part here is that each block-level element fills 100% of its parent elements’s width (<div class='page'> in this case), and they appear vertically one after another. Again, we’re essentially limited to a single-column layout.
Typically, you’d want to let the height of these boxes be determined automatically based on the content they contain; however, we’re more concerned with controlling layouts this chapter, so we won’t be dealing with much real content. This is why we need the explicit height properties.
It’s worth taking a look at what happens when we shrink an element’s width. Update our .sidebar rule to match the following:
The sidebar element gets narrower, but the rest of the boxes stay in the exact same position. All the blocks are still rendered vertically one after another. This is the behavior we’ll be changing with floats.
Floating an Element
The CSS float property gives us control over the horizontal position of an element. By “floating” the sidebar to the left, we’re telling the browser to align it to the left side of the page. Go ahead and float our sidebar with the following line:
However, this doesn’t just align the sidebar—it also tells surrounding elements that they can flow around the sidebar instead of beginning underneath it. It’s as if the sidebar is inside the .content block, so any HTML markup in .content would wrap around the sidebar’s box. This gives us a magazine-style layout:
You can also float elements right, as shown below (let’s keep our sidebar floated left though). Or, if you’re overriding a float declaration, you can cancel it with the none value. These are the most common values for the float property.
We now have all the tools necessary to align block-level elements: floats for left/right alignment and auto-margins for center alignment. Remember that this only applies to block boxes. Inline boxes are aligned with the text-align property, as discussed in the previous chapter.
Floating Inside of Parents
Floated boxes always align to the left or right of their parent element. In our example, the sidebar’s parent is <div class='page'>, which is as wide as the browser window. This is why our sidebar floats to the far left of the page.
Let’s change this by giving our page a fixed-width layout. Once again, the auto-margin centering technique comes in handy. Add this to styles.css:
margin: 0 auto;
Now, we can see that .sidebar floats to the left of the .page container, opposed to the edge of the browser window.
Positioning nested container divs like this is how you build up sophisticated website layouts. Here, we started with .page to center everything, then we left-aligned a sidebar inside that centered page. Things can get way more complex, but our simple example demonstrates the universal truth of CSS layouts: everything is a box inside of a box inside of another box.
Let’s examine our current magazine-style float a little bit more by adding an explicit width to our .content block:
This clearly demonstrates that our sidebar is in fact inside the .content block: if you take a screenshot of them, you’ll have an image that’s 650 pixels wide opposed to 850 pixels (our sidebar is 200 pixels wide).
This kind of float behavior is nice for images (which we’ll see later on), but for page layout, we actually want the content block to be next to the sidebar instead of flowing around it. For this, we need to tell the content block to float left, too. Add one more line to the .content rule:
When you float multiple elements in the same direction, they’ll stack horizontally, much like the default vertical layout algorithm, except rotated 90 degrees. The above code causes our entire content block to appear on the right of the sidebar instead of wrapping around it.
This gives us true control over the horizontal alignment of our block boxes. Try playing with the float values for both .sidebar and .content, and you’ll find that we already have a couple of distinct layouts at our disposal:
Make sure both of them are floating left before moving on. That takes care of the layout for the sidebar and content blocks, but it unfortunately messed up our .footer element…
After a Float
You probably noticed that our footer shows up in the top right, directly below .menu. That’s because floated boxes are removed from the normal flow of the page. The height of our floated elements don’t contribute to the vertical position of the footer, so it simply sticks itself below the last element that wasn’t floated.
We can see this more clearly by adding a red border around our .page element:
Notice how the border is only around the .menu and .footer elements. It’s as if the floated elements weren’t even there. There are two ways to fix this: clearing a float and hiding overflow.
“Clearing” a float is when we tell a block to ignore any floats that appear before it. Instead of flowing around the floated box, a cleared element always appears after any floats. It’s like forcing a box back into the default vertical flow of the page.
We can use the clear property to make our .footer drop down to the bottom of the page:
Usually, you want to clear both left and right floats as we did here, but you can choose to clear only one or the other with the left or right values. Note that the red border now wraps all the way around the footer, indicating that the floated elements indeed count towards the height of the .page container:
Depending on the type of layout you’re trying to create, this is a perfectly acceptable solution. We could stop here, but we’re going to explore float behavior more by transforming our page into a full-bleed layout that has background colors filling the entire browser window.
Watch what happens when we take the menu and footer out of the .page element. Change the <body> element to match the following:
Since .menu and .footer are outside our fixed-width .page, they’re the full width of the window, which is exactly what we want for a full-bleed layout. However, notice how .page has zero height again despite the fact that the footer still clears the sidebar and content blocks.
Once again, the only elements in .page are floated, so they don’t count towards its height. In other words, moving the footer outside of the .page container broke our clear fix.
Clearing floats only fixes the height issue when there’s an element inside the container element that we can add a clear property to. Now that our footer is outside .page, we need a new way to make floated elements contribute to the height of their container.
The solution is the CSS overflow property. By adding an overflow: hidden declaration to a container div, we’re telling it to recognize the height of any floated elements it contains. This is how we can add a background color to our .page element and have it actually render:
margin: 0 auto;
overflow: hidden; /* Add this */background-color: #EAEDF0; /* Add this */
You should now be able to see a light gray background in .page instead of the default white. This isn’t full bleed yet (we’ll address that in the next section). The important part here is the behavior of overflow: hidden. Without it, we wouldn’t be able to see the .page container’s background because it would have zero height.
To summarize, when you have an extra unfloated HTML element at the bottom of a container div, use the clear solution. Otherwise, add an overflow: hidden declaration to the container element. The underlying idea for both options is that you need a way to tell the browser to incorporate floats into the height of their container element in order for their backgrounds to show up.
Next, we want to make our .page background fill the entire browser window without changing the alignment of our sidebar or content blocks. The problem is, our .page is busy centering everything—we can’t use it for a full-bleed background because centering requires an explicit width property.
It’s time for another container div. Putting a box around .page lets it continue centering stuff while giving us a place to define a background-color property. Change our <body> element to match the following:
<body><divclass='menu'>Menu</div><divclass='container'><!-- Add this --><divclass='page'><divclass='sidebar'>Sidebar</div><divclass='content'>Content</div></div></div><!-- Add this --><divclass='footer'>Footer</div></body>
Remember that the default block-rendering behavior is for elements to fill the width of their container. So, we should be able to move our background-color declaration to a .container rule to get a full-bleed background:
As in the previous section, we still need the overflow: hidden line to force the .container to pay attention to the height of the floated elements. Without it, we wouldn’t see our background color because .container would have zero height.
This gives us three nested <div> elements just for laying out our page: a .container wrapper for full-bleed background color, a fixed-width .page for centering everything, and finally left-aligned .sidebar and .content blocks. This kind of nesting and aligning is pretty typical of most website layouts.
Floats for Equal-Width Columns
So far, we’ve seen a sidebar layout, a fixed-width layout, and a full-bleed layout. Floats can also be used to create multi-column layouts. This works just like our .sidebar and .content floats—we just have more of them.
Next we’re going to add three equal-width columns to our footer. Update the <footer> element, like so:
We can style each of these columns just like we laid out the rest of our page. Add a new rule to styles.css:
background-color: #B2D6FF; /* Medium blue */
This is the first time we’ve used percentage values instead of explicit pixel values. Percentages in CSS are relative to the width of the parent element. The result is three columns that automatically resize to one-third of the browser window. Resize the browser window, and you’ll see our columns grow and shrink accordingly. This is the beginning of responsive design.
Anyhoo, let’s not lose sight of the central thesis of this chapter: floats let us stack things horizontally instead of vertically. By changing the widths of the elements we’re floating, we can get all kinds of different layouts, from sidebars to multiple columns to grids.
Floats for Grids
Want a grid in the footer instead of 3 columns? No problem! When there isn’t enough room to stack a floated element horizontally, it pops down to the next line. All we need to do is add some more .column elements:
Our footer background is too short. Fortunately, we already know how to fix that. Let’s replace the footer’s explicit height with another overflow: hidden so it can accommodate any number of grid items:
You can use this same technique to make grids of any size. For example, creating a photo gallery with a bunch of thumbnails is simply a matter of putting the grid items in .page instead of the footer and adding <img/> elements to them. But, again, remember that flexbox is a more modern way to create these kinds of layouts.
A Brief Note on Naming Conventions
The .column class name isn’t exactly accurate anymore. This scenario is a good example of why we want to avoid class names that refer to appearance. “Column” isn’t so great because the content it contains doesn’t necessarily need to be rendered in multiple columns (e.g., for a mobile layout, there would likely only be one column). A better name would be something like .footer-item, but we’ll leave that for you to fix.
Floats for Content
There’s two aspects to defining a web page layout. You have your overall page structure, which we’ve been working on throughout this entire chapter. This is stuff like where you sidebar goes, how big your navigation menu is, etc. The other aspect of layouts is styling the individual HTML components (your actual content) that go inside this overarching page structure.
The process for the latter is the same, it’s just nested inside the former. Let’s add some dummy content to our .content element so we have something to play with:
<divclass='container'><divclass='page'><divclass='sidebar'></div><divclass='content'><imgsrc='?'class='article-image'/><p>Ad netus sagittis velit orci est non ut urna taciti metus donec magnis
hendrerit adipiscing mauris sit a proin ultrices nibh.</p><p>Enim suspendisse ac scelerisque nascetur vestibulum parturient sed mi a
dolor eu non adipiscing non neque scelerisque netus ullamcorper sed
parturient integer.Eros dui risus non sodales ullamcorper libero a dis
cubilia a orci iaculis cursus.</p><p>Egestas at aliquam a egestas accumsan cum elementum consectetur conubia
tristique eu et vitae condimentum in ante consectetur suscipit a a duis
vestibulum gravida morbi sagittis.Parturient scelerisque facilisis
ullamcorper a a pretium a nisl parturient semper senectus accumsan ipsum
mus scelerisque eget ridiculus.Accumsan dolor a.</p><p>Ligula taciti vel primis sit a tincidunt habitant parturient parturient
in parturient ante nulla consectetur sem.Facilisis parturient litora.</p></div></div></div>
We’ve got an image and several paragraphs that we can style just like our structural divs. For example, let’s create a magazine-style layout by floating the image and letting the text flow around it. Add a couple more rules to our stylesheet:
Notice how we have a float inside of a float, and everything works just fine. Laying out a website is a recursive process: you build a high-level structure to work in, then you fill it with your actual content. More complex layouts may need another layer or two of nesting, but the idea is the same.
Hiding Overflow (For Content)
You’ll find examples of nested layouts all over the place. For our final example, consider a basic user-comment thread. You have an image that’s floated left with a heading and some text next to it:
Let’s try creating this in our footer. In your favorite .column element, add the following:
<divclass='column'><divclass='avatar'></div><h3class='username'>Bob Smith</h3><pclass='comment'>Aptent vel egestas vestibulum aliquam ullamcorper volutpat
ullamcorper pharetra hac posuere a rhoncus purus molestie torquent. Scelerisque
purus cursus dictum ornare a phasellus. A augue venenatis adipiscing.</p></div>
This highlights another use case for our overflow: hidden trick. Sticking it on our .comment box made sure that the text “horizontally cleared” (that’s not a technical term) the floated image. Without it, the last line of the .comment text would hang underneath the image.
In other words, overflow: hidden breaks the magazine-style layout from the previous section, but in a very useful way.
This chapter was our first encounter with realistic web page layouts. We learned how to float divs to the left and right, how to deal with content after a float, and how to combine floats with the auto-margin centering technique from the CSS Box Model chapter. These are the tools we need to create sidebars, grids, an magazine-style layouts.
It’s important not to lose sight of the developer’s role in the website creation process. Your job as a web developer is to take a beautifully designed mockup and turn it into the HTML and CSS that browsers can display to your end users. Floats are a big leap forward towards that end, but they’re also becoming obsolete in favor of the flexbox layout scheme.
In the next chapter, we’ll learn even more ways to lay out complex websites using flexbox. The CSS properties will be new, but the process will be the same as it was in this chapter: we’ll still be aligning boxes inside of other boxes, inside of other boxes, and so on until we accomplish the desired layout.