CSS Layout with HTML5

Tutorial: CSS Layout with HTML5


csslayoutA trapeze artist performing a “layout” maneuver, which has very little in common with CSS layout but is nevertheless quite elegant. ๐Ÿ™‚

We introduced core HTML and CSS concepts in our CSS 101 and HTML 101 tutorials. This time, we’re going to crank it up a notch and show you how to use CSS for actual page layout and prettification. And since it’s 2011, we’ll take advantage of a handful of HTML5 tags for improved semantics. We’ll even learn to use a couple of the most popular features in CSS3, as well as custom typography with Google Web Fonts.

This tutorial is meant to be done step-by-step, working your way up from a bare HTML5 skeleton to a fully functional brochure site for an imaginary plumber (though this design could easily be adapted to suit a blog or news site). Note that we’re going to build a serviceable design, not a drop-dead gorgeous one – our focus is on learning techniques of modern web development. While you’re free to substitute in your own graphics or layout ideas, we recommend working all the way through the tutorial as written first, making sure you understand each step along the way. Feel free to tweak it for your own purposes later.

Here’s how our finished page will look:


Or see the finished site in your browser.

Getting Started

HTML5 introduces a set of new tags that let mark up your content with better semantics. For example, instead of using meaningless divs like:

we can use these shiny new elements:

That’s wonderful for semantics (making your code more easily understood by search engines and more interoperable with web services), but raises a problem – what happens when older browsers visit, who don’t understand the new tags? After all, browsers simply ignore tags and attributes they don’t understand, right? Fortunately, this problem is easily solved. A bit of Javascript called Modernizr knows how to detect these browsers and inject awareness of the new tags into the Document Object Model, or DOM (don’t worry about it if you don’t know what that means). Once present in the DOM, they can be styled with CSS just like modern browsers. That of course doesn’t give full HTML5 functionality to older browsers – they still won’t be able to use all features of HTML5 – but they will know how to “see” the new elements.

Rather than futz around installing Modernizr and setting up a workable starter template, we’ll use an empty HTML5 “container” page from a service called html5boilerplate.com, which will get us off the ground. For this tutorial, we’ve packaged up a slightly modified version of the html5boilerplate along with our own custom images and a bit of Javascript we’ll need in one portion of the tutorial.

โ†’ Download tutorial files โ†

Download that package and unzip it. Make sure you end up with a folder called “layout_tutorial”. The folder structure you see inside should look like this:


The numbered html and css documents are linked to each other. As you work your way through this tutorial, you can either:

  1. Stay in index0.html and style0.css the whole time, copying and pasting updates, working your way up to a finished product
  2. Switch between files progressively (index1.html, then index2.html, etc.), studying the changes along the way

The first method is a bit more hands-on, but some readers will find that it’s easy to make mistakes. The second method is more fool-proof, but possibly a bit less educational since you won’t be actually making the changes yourself.

I’ll list the page version at the top of each tutorial section in case you want to use method #2. From here on, I’ll just refer to index.html or style.css – it’s up to you to determine whether you should be in a numbered file or are working on your own.

To get started, open up index0.html and css/style0.css in your favorite text editor. If you use TextMate for Mac, just drag the whole tutorial folder onto the TextMate icon.

Now open up the same HTMl document in the browser of your choice (pull down File | Open and navigate to the HTML document we’re currently working on. You’ll see a blank document – that’s OK.

We’re not going to make any changes in this step – just take a look around to familiarize yourself.

Structure Your Document

index1.html and css/style1.css

Take a look at index1.html in your editor, and notice that it has three main sections: A <header> container, a <div id="main"> and a <footer> (note the use of the new HTML5 tags header and footer.) All are wrapped in a <div id="container">. The site we’re building will also have a navigation section and a sidebar. In order to prevent everything on the page from being invisible, we need a tiny amount of text content in each section as well. So modify the “container” section of the boilerplate so it looks like this:

Notice that we’ve also replaced <div id="main"> with <section id="main"> . People differ on whether the new <section> tag should be used in this way – some feel that <section> should be reserved for repeating sections of a page rather than to denote a whole content area like this. Your choice, but please stick with this usage for this tutorial.

Just to keep up good habits, be sure to put something in the <title> container – it’s easy to forget and later end up with a document that shows up in search results as “Untitled Document.” Refresh the browser and you’ll see nothing but your filler words. Let’s add some colors to our major elements so we can see what’s going on.

Now take a look inside of style.css. Whoa, that’s a lot of stuff! Here’s where html5boilerplate is doing a ton of heavy lifting for you, taking care of cross-browser incompatibilities so your page looks as close to identical in as many browsers as possible. Search the document for “Primary styles” about 3/4 of the way down. There’s a blank space where we’ll be adding our own styles, overriding any default provided styles. We’ll be working in the Primary Styles section throughout this tutorial.

Add the following simple style rules:

Isn’t it nice being able to call those sections by their actual, semantic names rather than specifying lots of arbitrary IDs and classes? Save the stylesheet and the HTML and refresh your browser. You should see something like this:


Things are going to look ugly for a bit, but don’t worry – our design will come together soon.

Throughout the rest of this tutorial we’ll often be modifying existing rulesets. In those cases, I’ll designate the new or changed lines by placing an asterisk in comment syntax at the end of the line. For example, if you already have this div#container :

and it’s time to add a new line to it, I’ll display it like this:

That way, if you copy and paste the code, the comment lines won’t affect functionality of your site. HTML samples will use HTML-style comments of course.

Let’s give some of these elements starter heights so we can start to visualize the layout. Modify these sections of the CSS:

Before we move on, let’s add some filler text to the content area and sidebar in index.html so we can see how they behave when we start to lay them out. Replace the text in the main content area with two paragraphs of filler text. If you’re using TextMate, type the word “lorem” then hit the tab key, or use your favorite lorem ipsum site to generate it for you – I used Hipster Ipsum here because I’m tired of reading Latin all the time ๐Ÿ™‚

Be sure to wrap your filler text paragraphs in <p> tags!

In the sidebar section, let’s create two short lists, with H2s as headers:

As soon as you refresh the page, you’ll notice something unexpected – gaps of white between some of the sections where you expected color to be.

Default Margins

Using your favorite debugging tool (in my case Chrome’s WebKit Inspector, though you may prefer Firebug for Firefox ), we can see what’s causing this:


As you roll over the second paragraph, notice that its containing box extends below the bottom of the text, into no-man’s land (hence the white gaps). The panel on the right says that the User Agent Stylesheet is putting 1em of margin above and below the paragraph. In other words, we’re seeing the browser defaults here. But wait – we don’t WANT all of our text crammed up against the sides of their containers, right? Let’s create a rule that will create padding in the main content section, sidebar, and footer. This will not only make the text look more “comfortable,” but it will also have the effect of overriding the browser’s default style that created those weird gaps. We can kill two birds with one stone! Since we can conveniently combine selectors into single rulesets using the CSS “comma” syntax, this is easy. Add this:

(It’s OK that we already have a section#main rule earlier in the stylesheet – these will be changing. Much nicer!

Now, since we don’t want our design stretching full-width across the browser, let’s give the content area a width, and center it on the page. Add this below your custom styles:

div#container means that this ruleset will apply to any div tag with an ID of “container,” thus matching the wrapper div that came with the boilerplate. We chose 960px because most monitors out there have a resolution of 1024px or wider. Since browser scrollbars take some of that horizontal width, 960px is a common conventional width for contemporary web designs.

margin:auto; is the magic incantation that causes unspecified margins to be calculated automatically and equally. The end result is that the containing div is centered on the page. We add some top margin to give the design some breathing room.

Let’s get our content area and sidebar lined up. We know that our container is 960px wide. Let’s say we want our sidebar to be 200px wide, leaving 760px for content and nice wide videos. Modify your section#main and aside rules like this:

What you end up with is this:

Div Widths

A start, but not quite what you’re looking for. Right now, all block-level elements are in the normal “document flow,” so they’re stacked on top of one another. We can disrupt the document flow by “floating” the two elements. When an element is floated, either to the left or right, it’s placed up against the left or right side of the box its in, and content flows around it. Try making these changes:

But wait! Why aren’t the content area and sidebar floating side by side? Do they not fit into the 960px container? 760 plus 200 is 960, right? Yes, but that’s not the whole story. When dealing with boxes in CSS, always remember that the total width of a box is:

Total box width = box size + margins + padding + border widths

Memorize this! It will bite you if you don’t. So… remember that earlier we put 10px of padding on section#main and aside. That means that in reality, both boxes are 20px wider than specified – the sidebar is actually 220px wide, and the content area is actually 780px wide. Added together, they don’t fit into the 960px container. To clarify this for yourself, bring up your trusty Firebug or WebKit Inspector and roll over the divs, studying their dimensions.


So we need to shave 20px of width from the specified dimensions of the sidebar and content area. Change them like this:

Cool! It’s working, but what happened to the footer? The problem is that it’s been swallowed up by the two floats, both of which contain content taller than the height of the footer. While it might be tempting to solve this by specifying heights for the content area and sidebar, don’t! You have no idea how much content is going to be in those sections, and you want to be flexible enough to accommodate any amount of content.

The right solution is to “clear” the footer. The “clear” declaration tells an element to not start appearing until the object to the left, the right, or on both sides has finished drawing. Most of the time you’ll want to clear on both sides. Modify your footer CSS like this:

Excellent – this is starting to look like a real web page.

Clear Both

Equal Height Boxes

index2.html and css/style2.css

One obvious remaining problem is that you can see the default white page background color where the shortest content box ends. If we later disable our temporary/starter colors so the content area is white, it won’t be a problem – the user will never see it. But let’s assume for a moment that we intend to keep the current color of the content area background.

This is a bit of a sticky problem for CSS, and there are many possible solutions out there. Some involve using JavaScript or JQuery, while others are pure CSS. While it would be nice to stick with pure CSS, those solutions are considerably more difficult, and there’s nothing significant lost by using a Javascript solution. Since the boilerplate template already loads in JQuery, we’re halfway finished.

First, in index.html, surround the sidebar and the content area in a new div with an ID of boxes, so it looks like this:

The Javascript will examine the height of all boxes inside this container, determine which one is tallest, and set the height of the other boxes in it to the same height. And the cool thing is, it will do all of this at run-time, so it will work with any amount of content in either box. Conveniently, our HTML5 boilerplate comes with a JavaScript plugins file, read to modify. Open up js/plugins.js, scroll to the end, and paste in the following:

To activate the script, paste this into the bottom of your index.html document, just before the closing </body> tag:

Your page should now look like this:

Equalheight Fixed

Did it work? Now try reversing things - add more content to your shortest column to make it the longest. Refresh the page and it should still work. Problem solved! And if someone doesn't have Javascript enabled, the worst that will happen is that they'll see a bit of the wrong color behind one of your boxes (people surfing with Javascript off in 2011 are used to things being broken all over the place).

That's it! We've got a basic CSS layout in place. Time to doll things up.

Extra credit: To test whether you've got a good handle on what we've done so far, try moving your sidebar to the left-hand side of the page.

Styling Your Design

index3.html and css/style3.css

Time to start making this dummy site look like a real site. Let's start by adding a site title, background image, and logo to the header area. But since we'll have a logo, do we need the site title to appear there as well? Yes and no. Yes, search engines will need that text present for SEO reasons. But it would be visually redundant. To resolve this dilemma, we're going to place the site title in an h1 inside the header, then move it off-screen with CSS. That way it's still there semantically, but won't disturb our design.

Change your header data in index.html as shown:

Now let's move that heading 3000 pixels off to the left of the screen visually by adding this to your stylesheet, style.css:

Notice that many CSS values can take negative numbers, giving you full control over placement - even allowing you to hide things completely! (note that this is just one technique for hiding objects with CSS).

Now let's add a background image to the header. Since we know our banner is 960x150px, we've prepped an image in Photoshop at those dimensions - it's in your tutorial "img" folder as old-plumbing.jpg. To use that image as the background for the header container, add this CSS:

Background images can be tiled infinitely within a box, or just horizontally or just vertically. In our case, the background image is exactly the same size as the box it lives in, so we don't need to think about tiling rules here.

We also need a logo to position on top of the background. For this tutorial we created a simple PNG with transparency in Photoshop at 400x133px - it's acme.png in your "img" folder. Since a box can only have one background image, we'll need to add this to our HTML directly, laying it on top of the background:

Notice that we gave the img tag a custom ID so we can address it in our CSS and control its positioning precisely. :

We used position:relative on the headerimg ID, which means that all positioning in that box should occur relative to the position it would occupy by default. Tweak these values until your logo sits right where you want it.

Background image courtesy freewebpageheaders.com

Your design should now look like this:

With Headerimg

Building a Nav Menu

index4.html and css/style4.css

OK, it's time to build our navigation menu. Since menu building can get a bit tedious, some people prefer to use a menu "system" rather than build from scratch - there are dozens of free/open source menu building options available out there. The basis of the technique used here is outlined in the Lists as Menus section of our CSS 101 tutorial - you might want to have a look at that before returning here.

Essentially, the idea is that we're using a series of nested unordered lists, where the top-level list items are our top-level navigation items, and the lists nested under those represent the contents of the drop-down menus. We use CSS syntax we've already covered to define the look and feel of the menu items in each of their states:

Notice that the nested ul is completely contained within a list item! Start by pasting a set of nested lists into your nav element:

And replace the the "nav" rule in your stylesheet with the following:

This CSS is going to look more complex than what you're used to working with so far, but if you take your time and think about each line, it's not hard to figure out what it's doing. Notice that we've added CSS comments to some sections as a reminder to our future selves - when we return to this to make changes in two years time, we shouldn't have to figure out the non-obvious stuff all over again.


It's time to let go of the green placeholder color we gave to the nav element - you now want it to match the background color of our menu so everything is seamless. So, change that now:

Your navigation should now look pretty much perfect!

CSS3 Gradients

index5.html and css/style5.css

Let's add some content to the footer, and style it. We'll place a specially styled paragraph and a list, as well as copyright and contact information. Replace the blank footer section of index.html with this:

Since the newly added elements are all contained within the "footer" element we'll be able to address them with custom CSS rules easily.

For the styling, we'll use a relatively new technique made possible by CSS3 - built-in gradients! For newer browsers, it's no longer necessary to create a gradient image file and load it in as a background (though you'll still need to do that to make older browsers happy).

Start by making the same background color change to the footer element that we made to the nav element above (i.e. replace your placeholder color). Let's also make the text white and add an additional rule that will let us give a different color to links found within the footer area:

We've provided a gradient image (img/blue_fade.png) created in Photoshop to make older browsers happy.

The key to making your gradient match the color palette of the site is to make one end of the gradient have the same color as another element in the design. In this case, our gradient uses the blue of the nav area background on one end, fading to a darker shade of the same color.

Since you're using a modern browser, you'll want to test the background image without the newer CSS3 technique first, so you can see how it will look for the rest of the world. Add this to your footer rule:

Why is the footer height set to 120px here rather than 140px? Even though the "footer" element is specified as 120px high, it's going to be taller than that in practice, thanks to box math - our stylesheet is putting 10px of padding inside the footer, so the real height is 140px!

Now to build a similar gradient using CSS3, which newer browsers will use automatically. In the future, when we decide there's enough browser support for CSS3 gradients out there, we can drop the background-image declaration. Because CSS3 isn't fully baked into the spec yet, we need to use a set of rules specific to various specific browsers. See the four similar background-image lines below? As you're working out your colors, only one of those is going to apply to the browser you're currently developing with. Safari and Chrome users should use the "webkit" line, Firefox developers should focus on "moz," Internet Explorer people should use "ms" and Opera devs should use the "o" line.

Once you've got the colors dialed in for the browser you're currently using, simply copy and paste the same values into to the other three lines, so your gradients will look exactly the same in all modern browsers. There's a lot more you can do with CSS3 gradients, but this is plenty for our purposes.

Your footer should now look like this:


A nice start, but all of that text hanging off the bottom of the footer needs fixing. Rather than have the "About" text go all the way across the footer, let's give it a set width and "float" it left, so other content in the footer wraps around it. Meanwhile, we'll float the contact list to the right side. Just as we did when creating the initial page layout, we'll need to put a "clear:both" on the footercopy rule so it doesn't try and jam itself up into the sections above. Here's the complete set of footer rules you'll need. This is slightly fiddly stuff - you'll need to tweak these rules to match your needs.

Rounded Corners

index6.html and css/style6.css

Getting tired of looking at all of those square corners? Let's smooth out the design a bit by giving the outer rectangle a border and slightly rounded corners. In the bad old days, we resorted to all kinds of tricks to achieve this effect, including making tiny rounded curves in Photoshop and setting them as table cell backgrounds. Yikes! But with CSS3, we get rounded corners almost for free. This won't work in older browsers, but that's OK - they can live with the rectangular design, no harm done (browsers simply ignore rules and tags they don't understand). Since you want a border to go all the way around your design, you'll need a new declaration on your div#container:

If the border-radius declaration were universally recognized, all you'd need to add would be this:

Cool, right? But wait - what's with the corner of the header image poking out beyond the border? Unfortunately, that's a bug. The best way to avoid it is to not use border-radius for boxes that contain image backgrounds. If you absolutely must, here's a workaround that works in most browsers:

... but it's not perfect, as you can see. More advanced workarounds for this problem exist, if you're feeling intrepid - Google for more info.

At this time, recent versions of Chrome, Firefox, Safari and Explorer all support "border-radius" as shown above. If you want to make sure your design works in earlier versions of Firefox, duplicate your radius rules with a "-moz" prefix, e.g. use both of these:

You can also specify radii on a per-corner basis with:

Don't want simple radii? You can specify different horizontal and vertical numbers to get some interesting effects, such as this:

Which will get you this:

Asym Radii

All kinds of weird and wonderful shapes are possible. For more, see CSS: border-radius and -moz-border-radius

Spacing the Content Area

index7.html and css/style7.css

So far we've pretty much ignored the main attraction - the content area. Let's pretty that up with proper spacing, a bit of typography, and a floated image.

Take a look at the red boxes in the image below. Evening out differences in spacing like this will go a long way toward giving your design professionalism and polish.


We're pretty happy with the spacing above the headline. Let's give the left margin the same amount of space.

Here are the styles we've got so far that apply to section#main:

We don't want to add padding to the second rule there, because that will also add padding to the sidebar and footer, which we don't want. Let's change them to this:

Note that we removed the section#main selector from the second rule. We also commented out the placeholder background color for the content area since we don't need it anymore. And we added 25px of left and right padding to the section#main rule. But whey did we reduce the width from 740px to 710px? Because we increased the horizontal padding by 15px on each side of the box, which increased its total width by 30px. To prevent our design from falling part, we had to reduce the overall size of that box by the same amount.

How's the spacing now? Much better!

Better Spacing

Typography on the Web

index8.html and css/style8.css

Right now, the font we're seeing throughout our design is the browser default. It may look OK to you now, but who knows what other users will see? It's important to specify it somewhere so you have a least a modicum of control over what gets displayed. Let's set a default font for the whole site in a "body" selector, which you should add at the top of your custom styles.

Since the body tag surrounds everything, and CSS rules cascade down to all contained elements, this declaration applies to everything on the page. That gives us a good safe fall-back, but is not gorgeous. While we could have our pick of the 18 commonly-installed fonts available on virtually all Mac and Windows machines, what a yawn! Real typography is finally available on the web through providers like Adobe TypeKit and Google Web Fonts. TypeKit is more advanced and lets you work with virtually any font for which licensing is obtainable, while Google Fonts are 100% free, and cab be implemented without setting up an account. For this exercise, let's stick with Google Fonts.

While you can use as many Google Fonts as you like, I find that most of them work much better as headlines or decorative text than as body text; it's tough to find a custom font that works better than the usual crew of Arial, Verdana, Georgia.

Browse through their collection and find one that you like (we'll skip the advanced typography discussion for now - that rabbit hole goes as deep as you want it to.) Click the Quick Use link below the font.

Gf Quickuse

Google will provide a box labeled "Add this code to your website." Copy the line you find there, and add it somewhere inside the <head> section of your HTML document. Your document head should now contain something like this:

You can now reference these custom fonts from your stylesheet wherever you like. I want to use the native Tahoma font for body text and Google's Kreon for headlines, so I make the following changes to my stylesheet, right below the section#main selector:

Note that I've manually fiddled with the size, margins, letter-spacing and line-height in both selectors to get things looking exactly how I want them. Play with the settings until things click for you.


Floating Images

index-finished.html and css/style-finished.css

We need a nice illustration or photo to doll up our text, with a caption. It would be nice if the text flowed around our captioned image neatly, with a bit of padding and a nice border. You already know how to float divs for page layout - here's how to do similar for images. For this example, you can either use img/wave.png from this tutorial or use your own image, then add this just below the article h1 in index.html:

We want the whole div - caption and all - to be floated left, so add this to your stylesheet:

Let's break that down. We use float:left to get the nearby text to wrap around it. We set width:200px so that both the image and the caption are contained in the same box - otherwise the caption text would jut way out to the right. We set margin-right to provide a gap between the edge of the box and the text, for breathing room (note we do NOT want that margin all the way around the image - just to the right, since it's floated left.) The 5px of padding provides a gap so that our border doesn't slam up against the side of the image. Finally, we apply some margin-top to match the top margin on paragraph text in our design - otherwise the top of the image would not align with the top of the nearby text. Here's what we've got so far:


The caption still has too much space above and below it. It would also be nice if it were smaller, and italicized. Easily accomplished with the following rule:

Here we're just erasing the default top and bottom margins that come with paragraphs, and tweaking the font's appearance. Much nicer!


About That Sidebar

The last remaining section is the sidebar, but we'll leave that as an exercise for the reader - you should be able to style that however you like based on what you've learned so far. Try changing its background color (or setting a tiled background image), changing the type, adding paragraph text and advertisement, etc. Challenge yourself!

About this Tutorial

This tutorial was written for Berkeley Advanced Media Institute and the UC Berkeley Graduate School of Journalism by webmaster Scot Hacker.

Republishing Policy

This content may not be republished in print or digital form without express written permission from Berkeley Advanced Media Institute. Please see our Content Redistribution Policy at multimedia.journalism.berkeley.edu/content_redistribution/.

Upcoming Workshops: