Sponsored by

  • Intel
  • HP

CSS3Tutorial

Create fluid layouts with HTML5 and CSS3

Create fluid layouts with HTML5 and CSS3

Ben Frain explains how to create fluid layouts by converting pixel-based grids to proportions.

When I first started making websites at the end of the 1990s, layout structures were table-based. More often than not, sectioning up screen real estate was done with percentages. For example, a left navigation column might be 20 percent whilst the main content area would be 80 percent. There weren't the vast differences in browser viewports we see today, so these layouts scaled well across the limited range of viewports.

Nobody much cared that sentences looked a little different on one screen compared to another. However, as CSS-based designs took over, it enabled web-based designs to more closely mimic print. With that transition, for many (including myself), proportionally based layouts dwindled for many years in favor of their rigid, pixel-based counterparts.

But like all things, proportional designs have come back around. The Mini, permed hair (I wish!) and flared jeans have all made their comebacks over the years. Now, it's time for proportional layouts to make a re-appearance.

  • Software: Text editor, browser
  • Project time: 1-2 hours
  • Skills: Learn why proportional layouts are necessary for responsive design, convert pixel-based element widths to proportional percentages, convert pixel-based typography sizes to their em-based equivalent, understand how to find the context for any element
  • Support file

01. Fixed layouts aren't future-proof

As I mentioned, since the 'table layout' days, I've had little call to use proportional layouts. Typically, I've been asked to code HTML and CSS that best matches a design composite that almost always measures 950-1000 pixels wide. If the layout was ever built with a proportional width (say, 90 percent), the complaints would have arrived quickly: "It looks different on my monitor". Web pages with fixed, pixel-based dimensions were the easiest way to match the fixed, pixel-based dimensions of the composite.

Even in more recent times, when using media queries to produce a tweaked version of a layout specific to a certain popular device such as an iPad or iPhone, the dimensions could still be pixel-based, as the viewport was known. However, while developers might enjoy the possibility of re-charging a client each time they need a site tweaked for today's newest gizmo, it's not exactly a future-proof way of building web pages. As more and more varied viewports are being introduced, we need some way of provisioning for the unknown.

02. Why proportional layouts are essential for responsive designs

Whilst media queries are powerful, we are now aware of some limitations. Any fixed-width design, using only media queries to adapt for different viewports, will merely 'snap' from one set of CSS media query rules to the next with no linear progression between the two.

Instead, we want to create a design that flexes and looks good on all viewports, not just particular ones specified in a media query. I'll cut to the chase: we need to switch our fixed, pixel-based layouts to fluid, proportional ones. This will enable elements to scale relative to the viewport until one media query or another modifies the styling.

03. Proportional layouts and media queries

Ethan Marcotte wrote the definitive article on Responsive Web Design at A List Apart. Whilst the tools he used (fluid layout and images, and media queries) were not new, the application and embodiment of the ideas into a single coherent methodology was. For many working in web design, his article was the genesis of new possibilities – new ways to create web pages that offered the best of both worlds: a way to have a fluid flexible design based on a proportional layout, whilst being able to limit how far elements could flex with media queries. Putting them together forms the core of a responsive design, creating something truly greater than the sum of its parts.

04. Amending a design from a fixed to a proportional layout

For the foreseeable future, any design composite you receive or create is likely to have fixed dimensions. Currently we measure (in pixels) the element sizes, margins, and so on within the graphics files from Photoshop, Fireworks, and so on. We then punch these dimensions directly into our CSS. The same goes for text sizes. We click on a text element in our image editor of choice, note the font size, and then enter the value (again, often measured in pixels) into the relevant CSS rule. So how do we convert our fixed dimensions into proportional ones?

05. A formula to remember

It's possible I'm coming off as too much of an Ethan Marcotte fanboy, but at this point it's essential that I provide another large tip of the hat (it should probably be a bow, maybe even a kneel) to him. In Dan Cederholm's excellent book, Handcrafted CSS, Mr. Marcotte contributed a chapter covering fluid grids. In it, he provided a simple and consistent formula for converting fixed width pixels into proportional percentages:

target ÷ context = result

Does that smell a bit like an equation to you? Fear not, when creating a responsive design, this formula soon becomes your new best friend. Rather than talk any more theory, let's put it to work converting the fixed-dimension design for the fictional movie website And The Winner Isn't... to a fluid percentage-based layout.

06. Embracing Fluid Layouts

At the minute, the basic markup structure of the site looks like this:

  1. <div id="wrapper">
  2. <!-- the header and navigation -->
  3. <div id="header">
  4. <div id="navigation">
  5. <ul>
  6. <li><a href="#">navigation1</a></li>
  7. <li><a href="#">navigation2</a></li>
  8. </ul>
  9. </div>
  10. </div>
  11. <!-- the sidebar -->
  12. <div id="sidebar">
  13. <p>here is the sidebar</p>
  14. </div>
  15. <!-- the content -->
  16. <div id="content">
  17. <p>here is the content</p>
  18. </div>
  19. <!-- the footer -->
  20. <div id="footer">
  21. <p>Here is the footer</p>
  22. </div>
  23. </div>

What's important to note here is the CSS we are currently using to set the widths of the main structural (header, navigation, sidebar, content, and footer) elements. I've omitted many of the styling rules so we can concentrate on structure:

  1.     #wrapper {
  2.       margin-right: auto;
  3.       margin-left: auto;
  4.       width: 960px;
  5.     }
  6.     #header {
  7.       margin-right: 10px;
  8.       margin-left: 10px;
  9.       width: 940px;
  10.     }
  11.     #navigation {
  12.       padding-bottom: 25px;
  13.       margin-top: 26px;
  14.       margin-left: -10px;
  15.       padding-right: 10px;
  16.       padding-left: 10px;
  17.       width: 940px;
  18.     }
  19.     #navigation ul li {
  20.       display: inline-block;
  21.     }
  22.     #content {
  23.       margin-top: 58px;
  24.       margin-right: 10px;
  25.       float: right;
  26.       width: 698px;
  27.     }
  28.     #sidebar {
  29.       border-right-color: #e8e8e8;
  30.       border-right-style: solid;
  31.       border-right-width: 2px;
  32.       margin-top: 58px;
  33.       padding-right: 10px;
  34.       margin-right: 10px;
  35.       margin-left: 10px;
  36.       float: left;
  37.       width: 220px;
  38.     }
  39.     #footer {
  40.       float: left;
  41.       margin-top: 20px;
  42.       margin-right: 10px;
  43.       margin-left: 10px;
  44.       clear: both;
  45.       width: 940px;
  46.     }

All the values are currently set using pixels. Let's work from the outermost element and change them to proportional percentages using the target ÷ context = result formula.

All our content currently sits within a div with an ID of #wrapper. You can see by the CSS above that it's set with automatic margin and a width of 960 px. As the outermost div, how do we define what percentage of the viewport width it should be?

07. Setting a context for proportional elements

We need something to 'hold' and become the context for all the proportional elements (content, sidebar, footer, and so on) we intend to contain within our design. We therefore need to set a proportional value for the width that the #wrapper should be in relation to the viewport size. For now, let's knock off a nought and roll with 96 percent and see what happens. Here's the amended rule for #wrapper:

  1.         #wrapper {
  2.          margin-right: auto;
  3.          margin-left: auto;
  4.          width: 96%; /* Holding outermost DIV */
  5.     }

And here's how it looks in the browser window:

Create fluid layouts
The site with a #wrapper width setting of 96%

So far, so good! 96 percent actually works quite well here, although we could have opted for 100 or 90 per cent – whatever set the design within the viewport in the most aesthetically pleasing manner.

Changing from fixed to proportional gets a little more complicated as we move inwards. Let's look at the header section first. Consider the formula again: target ÷ context = result. Our #header div (the target) sits within the #wrapper div (the context). Therefore, we take our #header (the target) width of 940 pixels, divide it by the width of the context (the #wrapper), which was 960 px, and the result is .979166667. We can turn this into a percentage by moving the decimal place two digits to the right and we now have a percentage width for the header of 97.9166667. Let's add that to our CSS:

  1.     #header {
  2.       margin-right: 10px;
  3.       margin-left: 10px;
  4.       width: 97.9166667%; /* 940 divided by 960 */
  5.     }

And as both the #navigation and the #footer divs also have the same declared width, we can swap both of those pixel values to the same percentage-based rule.

Finally, before we take a peek in the browser, let's turn to the #content and #sidebar divs. As the context is still the same (960 px), we just need to divide our target size by that figure. Our #content is currently 698 px, so divide that value by 960 and the answer is .727083333. Move the decimal place and we have a result of 72.7083333 percent – that's the width of the #content div in percentage terms.

Our sidebar is currently 220 px but there's also a 2 px border to consider. I don't want the thickness of the right-hand border to expand or contract, so that will stay at 2 px. Because of that, I need to subtract its thickness from the width of the sidebar, then perform the same calculation. Divide the target (now 218 px) by the context (960 px) and the answer is .227083333. Shift the decimal and we have a result of 22.7083333 percent for the sidebar.

After amending all the pixel widths to percentages, the relevant CSS looks like this:

  1.     #wrapper {
  2.       margin-right: auto;
  3.       margin-left: auto;
  4.       width: 96%; /* Holding outermost DIV */
  5.     }
  6.     #header {
  7.       margin-right: 10px;
  8.       margin-left: 10px;
  9.       width: 97.9166667%; /* 940 divided by 960 */
  10.     }
  11.     #navigation {
  12.       padding-bottom: 25px;
  13.       margin-top: 26px;
  14.       margin-left: -10px;
  15.       padding-right: 10px;
  16.       padding-left: 10px;
  17.       width: 72.7083333%; /* 698 divided by 960 */
  18.     }
  19.     #navigation ul li {
  20.       display: inline-block;
  21.     }
  22.     #content {
  23.       margin-top: 58px;
  24.       margin-right: 10px;
  25.       float: right;
  26.       width: 72.7083333%; /* 698 divided by 960 */
  27.     }
  28.     #sidebar {
  29.       border-right-color: #e8e8e8; border-right-style: solid; border-right-width: 2px; margin-top: 58px;
  30.       margin-right: 10px;
  31.       margin-left: 10px;
  32.       float: left;
  33.       width: 22.7083333%; /* 218 divided by 960 */
  34.     }
  35.     #footer {
  36.       float: left;
  37.       margin-top: 20px;
  38.       margin-right: 10px;
  39.       margin-left: 10px;
  40.       clear: both;
  41.       width: 97.9166667%; /* 940 divided by 960 */
  42.     }

The following screenshot shows the result in Firefox with the viewport around 1000 px wide:

Create fluid layouts
The developing fluid layout, viewed in Firefox

08. Can't we just round the numbers?

Let's take some time out from the layout to consider the issue of decimal precision. Some critics of responsive design techniques (for example, see this article by James Pearce) argue that entering numbers such as .550724638 em into stylesheets is daft. You may wonder yourself why they aren't simply rounded to something more sensible. The counter-argument is that unrounded values are a more accurate answer to the question being asked. Providing a browser with the most accurate answer should make it more able to display that answer in the most accurate manner.

As a related aside, if you stayed awake through more than a couple math classes, you will have heard of the Golden Ratio. The mathematical ratio, used in almost every discipline, is expressed as approximately 1:1.61803398874989 (if you want it to 10,000 decimal places, knock yourself out here). Not a neat number by any means, but quite an important one. If the Golden Ratio can suffer such precise measurements, I'm inclined to believe our web designs can too. Right, back to our fluid layout.

09. Converting the other layout elements

Now, let's go ahead and replace all the 10 px instances used for padding and margin throughout with their proportional equivalent using the same target ÷ context = result formula. As all the 10 px widths have the same 960 px context, the width in percentage terms is 1.0416667 percent (10 ÷ 960).

Everything still looks fine at the same viewport size. However, the navigation area isn't behaving. If I bring the viewport size in just a little, the links start to span two lines:

Create fluid layouts
Notice the problem with the site navigation?

Furthermore, if I expand my viewport, the margin between the links doesn't increase proportionally. Let's take a look at the CSS associated with the navigation and try and figure out why:

  1.   #navigation {
  2.       padding-bottom: 25px;
  3.       margin-top: 26px;
  4.       margin-left: -1.0416667%; /* 10 divided by 960 */
  5.       padding-right: 1.0416667%; /* 10 divided by 960 */
  6.       padding-left: 1.0416667%; /* 10 divided by 960 */
  7.       width: 97.9166667%; /* 940 divided by 960 */
  8.       background-repeat: repeat-x;
  9.       background-image: url(../img/atwiNavBg.png);
  10.       border-bottom-color: #bfbfbf;
  11.       border-bottom-style: double; border-bottom-width: 4px;
  12.     }
  13.     #navigation ul li {
  14.       display: inline-block;
  15.     }
  16.     #navigation ul li a {
  17.       height: 42px;
  18.       line-height: 42px;
  19.       margin-right: 25px;
  20.       text-decoration: none;
  21.       text-transform: uppercase;
  22.       font-family: Arial, "Lucida Grande", Verdana, sans-serif;
  23.       font-size: 27px;
  24.       color: black;
  25.     }

Our third rule, the #navigation ul li a, still has a pixel-based margin of 25 px. Let's go ahead and fix that with our trusty formula. As the #navigation div is based on 940 px, our result should be 2.6595745 percent. So we'll amend the code as follows:

  1.     #navigation ul li a {
  2.       height: 42px;
  3.       line-height: 42px;
  4.       margin-right: 2.6595745%; /* 25 divided by 940 */ text-decoration: none;
  5.       text-transform: uppercase;
  6.       font-family: Arial, "Lucida Grande", Verdana, sans-serif;
  7.       font-size: 27px;
  8.       color: black;
  9.     }

That was easy enough! Let's just check all is okay in the browser...

Create fluid layouts
The result of our change to the link layout: fixing one problem has created another

Oh wait: that isn't exactly what we were gunning for. Okay, the links aren't spanning two lines but we don't have the correct proportional margin value, clearly. The navigation links look like one big word, and not one I can find in my dictionary...

10. Always remember the context

Considering our formula again (target ÷ context = result), it's possible to understand why this issue is occurring. Our problem here is the context. Here's the relevant markup:

  1.     <div id="navigation">
  2.       <ul>
  3.         <li><a href="#">Why?</a></li>
  4.         <li><a href="#">Synopsis</a></li>
  5.         <li><a href="#">Stills/Photos</a></li>
  6.         <li><a href="#">Videos/clips</a></li>
  7.         <li><a href="#">Quotes</a></li>
  8.         <li><a href="#">Quiz</a></li>
  9.       </ul>
  10.     </div>

As you can see, our <a href="#"> links sit within the <li> tags. They are the context for our proportional margin. Looking at the CSS for the <li> tags, we can see there are no width values set:

    #navigation ul li { display: inline-block; }

As is often the case, it turns out that there are various ways of solving this problem. We could add an explicit width to the <li> tags, but that would either have to be fixed-width pixels or a percentage of the containing element (the navigation div) – neither of which allows any flexibility for the text that ultimately sits within them.

We could instead amend the CSS for the <li> tags, changing inline-block to inline:

  1.     #navigation ul li {
  2.       display: inline;
  3.     }

Opting for display: inline; (which stops the <li> elements behaving like block-level elements) also makes the navigation render horizontally in earlier versions of Internet Explorer (versions 6 and 7) that have problems with inline-block. However, I'm a fan of inline-block as it gives greater control over the margins and padding for modern browsers, so instead I'm going to leave the <li> tags as inline-blocks (and perhaps add an override style for IE 6 and IE 7 later) and instead move my percentage-based margin rule from the <a> tag (which has no explicit context) to the containing <li> block instead. Here's what the amended rules now look like:

  1.     #navigation ul li {
  2.       display: inline-block;
  3.       margin-right: 2.6595745%; /* 25 divided by 940 */
  4.     }
  5.     #navigation ul li a {
  6.       height: 42px;
  7.       line-height: 42px;
  8.       text-decoration: none;
  9.       text-transform: uppercase;
  10.       font-family: Arial, "Lucida Grande", Verdana, sans-serif;
  11.       font-size: 27px;
  12.       color: black;
  13.     }

And here's how the result looks in the browser with a viewport 1200 px wide:

Create fluid layouts
The updated layout viewed in a viewport 1200 px wide: that's one navigation problem fixed!

The navigation is getting there now, but I still have the problem of the navigation links spanning two lines as the viewport gets smaller, at least until I get below 768 px wide, when the media query we wrote earlier [in Chapter 2 of the book from which this article is an excerpt] overrides the current navigation styles. Before we start fixing the navigation, I'm going to switch all my typography sizes from fixed-size pixels to the proportional unit, ems.

11. Using ems rather than pixels for typography

In years gone by, web designers primarily used ems for sizing typography, rather than pixels, because earlier versions of Internet Explorer were unable to zoom text set in pixels. For some time, modern browsers have been able to zoom text on screen, even if the size values of the text were declared in pixels. So, why is using ems instead of pixels preferable?

Here are two obvious reasons: firstly anyone still using Internet Explorer 6 (yes, those two people) automatically gets the ability to zoom the text; and secondly, it makes life for you, the designer/developer, much easier.

The size of an em is determined in relation to the size of its context. If we set a font size of 100 percent to our <body> tag and style all further typography using ems, they will all be affected by that initial declaration. The upshot of this is that if, having completed all the necessary typesetting, a client asks for all our fonts to be a little bigger, we can merely change the body font size and all other typography changes in proportion.

Using our same target ÷ context = result formula, I'm going to convert every pixel-based font size to ems. It's worth knowing that all modern desktop browsers use 16 px as the default font size (unless explicitly stated otherwise). Therefore, from the outset, applying any of the following rules to the body tag will provide the same result:

  1.     font-size: 100%;
  2.     font-size: 16px;
  3.     font-size: 1em;

As an example, the first pixel-based font size in our stylesheet controls the site's title, And The Winner Isn't... at the top left of the screen:

  1.     #logo {
  2.       display: block;
  3.       padding-top: 75px;
  4.       color: #0d0c0c;
  5.       text-transform: uppercase;
  6.       font-family: Arial, "Lucida Grande", Verdana, sans-serif; font-size: 48px;
  7.     }
  8.     #logo span {
  9.       color: #dfdada;
  10.     }

As 48 ÷ 16 = 3, our style changes as follows:

  1.   #logo {
  2.       display: block;
  3.       padding-top: 75px;
  4.       color: #0d0c0c;
  5.       text-transform: uppercase;
  6.       font-family: Arial, "Lucida Grande", Verdana, sans-serif; font-size: 3em; /* 48 divided by 16 = 3*/
  7.     }

You can apply the same logic throughout. If at any point things go haywire, it's probable the context for your target has changed. For example, consider the <h1> within the markup of our page:

  1.     <h1>Every year <span>when I watch the Oscars I'm annoyed...</span></h1>

Our new em-based CSS looks like this:

  1.       #content h1 {
  2.       font-family: Arial, Helvetica, Verdana, sans-serif; text-transform: uppercase;
  3.       font-size: 4.3125em; } /* 69 divided by 16 */
  4.       #content h1 span {
  5.       display: block;
  6.       line-height: 1.052631579em; /* 40 divided by 38 */ color: #757474;
  7.       font-size: .550724638em; /* 38 divided by 69 */
  8.     }

You can see here that the font size (which was 38 px) of the <span> element is in relation to the parent element (which was 69 px). Furthermore, the line-height (which was 40 px) is set in relation to the font itself (which was 38 px).

But what on earth is an em?

The term 'em' is simply a way of expressing the letter M in written form and is pronounced in the same way. (Historically, the letter M was used to establish the size of a given font, since it is the widest of the letters.) Nowadays, em as a measurement defines the proportion of a given letter's width and height with respect to the point size of a given font.

Going further

By now, the structure of the website is resizing correctly when viewed in viewports of differing sizes, and we've switched our pixel-based type to ems. We still have to figure out how to scale images as the viewport resizes... but that's a topic for the book itself.

Words: Ben Frain

This article is an exclusive excerpt from Ben Frain's book Responsive Web Design with HTML5 and CSS3, published by Packt Publishing. The eBook edition currently costs £12.71, and the print edition £22.49, including the eBook. You can buy them both here.

Liked this? Read these!

Subscription offer

Log in with your Creative Bloq account

site stat collection