Fluid, Elastic, Fantastic!

logo
Notebook Last updated

A fundamental question when creating web pages is whether the layout will have a fixed width or whether it will be able to expand and contract depending on factors such as the width of the browser window (or viewport). Fixed-width, pixel-based layouts are predictable but not very adaptable to changing browser conditions. Fluid (or liquid) layouts—even with a minimum and maximum width set—are harder to control, especially if the design requires features like a full-width header image. Em-based designs—especially when combined with some fluid elements—in a sense combine the best of both worlds, as I’ll demonstrate here.

In an em-based design, both text and layout dimensions are measured in ems. An “em” is a relative unit whose length is determined by an element’s font-size. If the font-size is set at 16px, then 1em is equal to 16px. This measurement can be used for other elements, like the page wrapper. So a typical wrapper style might include the following:

#wrapper {
    width: 46em;
    margin: 0 auto;
}

This setting will create a centered, fixed-width design, but with the difference that, if the user increases the text size, the wrapper will also grow proportionately. This is much nicer than having text reflowing with every resize.

View Example 1

However, at some point the wrapper will become wider that the viewport, meaning that the user will need to scroll horizontally to view content, which is not very good.

To avoid this, add a max-width to the wrapper, like so:

#wrapper {
    width: 46em;
    margin: 0 auto;
    max-width: 94%;
}

That maximum could be set in ems, but I find a percentage better, as you don’t know how wide the user’s viewport will be.

View Example 2

Max-width prevents the layout getting too wide when resized, but what if the user’s viewport is narrower than 46em—either to start with, or if the user reduces the width?

Answer: if you set the width of the wrapper’s contents in percentages, the wrapper will contract horizontally as the viewport narrows. For example, if a #content div is placed within the wrapper and sized to width: 100%, the layout will narrow as the viewport is narrowed:

<div id="wrapper">
    <div id="content">
        <p>Content here…</p>
    </div>
</div>
#content {
    width: 100%;
}

View Example 3

Of course, columns can be floated and sized in percentages as well, such as:

#col1 {
    width: 60%;
    float: left;
}

#col2 {
    width: 30%;
    float: right;
}

View Example 4

That is the essence of a “fluid elastic” layout: elastic expansion until a max-width is reached, and fluid contraction as the viewport is narrowed.

Further Considerations

This kind of expanding and contracting layout may not seem very image-friendly. Background images don’t scale, so you will need to consider their use carefully. A vertically repeating image on the wrapper, for example, will need to be wide enough to accommodate the widest screens.

Embedded images can also be a problem. If you have a wrapper-width header image sized in pixels, for example, it will either be too narrow when the text size is increased or too wide if the viewport is narrowed. A nice solution to this is to give the image a percentage width:

#header {
    width: 100%;
    padding-bottom: 1em;
}

#header img {
    vertical-align: bottom;
    width: 100%;
}

Scale the viewport up and down and watch the header image magically scale! I’ve also placed images within the columns, also set to width: 100%.

View Example 5

Normally, you would want text in the header as well. It would be easy to make this part of the image, but ideally it should be real text. Here is one way to do that:

#header {
    position: relative;
    min-height: 3em;
}

#header h1 {
    position: absolute;
    top: 50%;
    left: 1em;
    font-size: 2em;
    margin-top: -1.8em;
    line-height: 3em;
}

The H1 element is positioned absolutely in relation to the #header div, and vertically centered with top: 50% and a negative top margin. If you scale the example below in a browser, you’ll see that the header text stays vertically centered at all sizes.

I also added a min-height to the #header div to make for a better appearance if images do not load—at least in decent browsers. (If images don’t load, it’s good to have text appear, and Alt text doesn’t cut it for me. Search engines will pick up an H1 element that is pulled off screen with a negative margin, but that won’t help users for whom images don’t load.)

View Finished Layout

Browser Blues

The layouts shown above only work partially in IE6 and below. The layout does scale on resize, but neither recognizes the max-width setting nor reflows when the viewport is narrowed. Well, this behavior is consistent with fixed width design anyway, so it’s no big drama. Just another reason to upgrade (or to check out a JavaScript fix or two or three [discussion here] or four).

Also, IE6 and 7 do not always handle the image scaling too well, sometimes creating jagged or blurry results—particularly if the image displays text or vector art. There are fixes for image scaling in IE, the simplest being to insert this code into your (preferably IE-specific) stylesheet:

img {
    -ms-interpolation-mode: bicubic;
}

Other solutions are discussed elsewhere, such here, here and here.

Acknowledgements & Links

Comments

Richard at Web Design Leeds — July 23, 2012

Interesting post. I’ve always used the clear:both method, though it’s always worth seeing what other people do.

In terms of tidy code, the best seems to be the overflow:hidden method, but that really seems to work against how I’d imagine it.

From that code, I would have thought that the overflow style would actually make most of the floated divs invisible since they appear mostly outside of the div when that style is not applied.

Ralph Mason — July 23, 2012

Thanks Richard. Yes, overflow: hidden is very handy, as long as you don’t need any visible overflow (such as when a logo hangs out of the container). It was Paul O’Brien who publicized the use of overflow for float containment, and his explanation of why it works is very interesting. I’ll just quote a snippet here:

The overflow:hidden (or even auto will work but will result in scrollbars if content is too big) works because overflow is a property that makes an element take control and look after the boundaries of its content - even so called invisible content like floats. Once overflow is applied it suddenly says “Hold on I’ve got some floats there” and stretches around them.

It’s worth reading the rest of the explanation.

Have Your Say