• Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint
Share this Page URL
Help

Chapter 4. Building Liquid Layout Struct... > Creating Liquid Columns Using Floats

Creating Liquid Columns Using Floats

At this point, since our divs are already liquid, all we need to do is stop the default top-to-bottom stacking on some of the divs and create some columns instead. There are a few ways to do so.

Absolute Positioning versus Floating

You’ll notice that none of the column-creating methods discussed in this chapter use absolute positioning—only floats. This is intentional. While absolute positioning can be used to create columns, most professional CSS developers don’t find it a robust way to create an entire layout. It’s much too rigid—even for fixed-width designs—because it pins a piece of content to an exact spot on the page. It can’t adjust to the content around it, and, unless you have a very simple layout, you almost always end up with content overlapping and other nasty surprises. Absolute positioning is best reserved for positioning small design elements, such as a search bar in a header, not for creating the overall structure of layouts.


Creating Columns with Floats and Matching Side Margins

A quick and easy way to create columns out of divs is to float the div or divs that you want to be on the edges of the page either to the right or the left, and then give the remaining div a matching margin facing the float to make room for it. In order for this to work, the floated div has to come before the non-floated div in the (X)HTML source for the page. This is because floating does not move content up—only over to either side. The content that follows the float is what moves up to sit beside the float.

Note

If you need a refresher course on float theory, see the extensive list of tips and links to articles and tutorials on floats at the Smashing Magazine article “CSS Float Theory: Things You Should Know” (www.smashingmagazine.com/2007/05/01/css-float-theory-things-you-should-know). Another excellent source is www.communitymx.com/abstract.cfm?cid=AC008, although it is not a free article.


With our basic div structure, all we need to do to see this in action is apply the following CSS:

#content-main {
   float: right;
						width: 75%;
   background: #FFFFDD;
}

This restricts the width of the main content div so it no longer spans the entire width of the window, leaving room for the sidebar div to move up to the main content div’s left side (Figure 4.2).

Figure 4.2. The main content div now takes up the rightmost 75 percent of the viewport, with the sidebar div taking up the remaining space to its left.


If, instead, you want the sidebar to be on the right side with the main content on the left, simply change the float: right to float: left. There’s no need to change the order of the divs in the source. The main content div will simply move to the left instead of the right, and the sidebar will just move up to its right to take over the remaining space.

The 75-percent width means that the main content div will always be 75 percent as wide as the width of its parent element—in this case, the body element. Since in this example the body doesn’t have any width assigned and just matches the viewport width, the main content div bases its width off the viewport as well. As you change the window size, the width of the main content div changes in proportion. The sidebar just takes whatever is left—in this case, 25 percent.

Note

Later in the chapter, we’ll look at what happens when the parent element does have a width assigned.


We now have two divs sitting side by side, but some funky things happen at the bottom of the page. If the main content div is longer than the sidebar, it overlaps the footer (as we saw in Figure 4.2). If the sidebar is longer, it wraps underneath the main content div (Figure 4.3).

Figure 4.3. If the sidebar is longer than the main content div, it wraps underneath.


In both cases, this is correct behavior based on the mechanics of floating. This book assumes you already know basic float theory, so we won’t get into the nitty-gritty of what’s going on with these divs, but the basic reason both of these oddities are happening is because floats only displace inline content, like text, not block-level elements, like the entire footer or sidebar divs. Floats are removed from the flow of the page, so other blocks act like they don’t exist and can get covered up by them.

Tip

Although we could have used clear: right instead of clear: both since the float we need to clear is on the right side, using a value of both makes our layout more “accepting” of changes in the CSS that might come later.


Although both of these display issues are correct, they’re usually not the look we want. Luckily, they’re quite easy to change by adding just a bit more CSS.

To fix the footer overlap, simply add the clear property to the footer to force it to sit below any previous floats (Figure 4.4):

#footer {
   clear: both;
   background: #DDDDDD;
}

Figure 4.4. The clear property on the footer moves it fully below the floated main content div.


Floating the Sidebar in Hybrid Layouts

You can float the sidebar instead of the main content div, but you’d have to put the sidebar first in the (X)HTML source, so there’s not much point to doing so—unless you’re creating a hybrid layout. If you want the sidebar to be a fixed number of pixels or ems wide, and you want the main content div to just take up the remaining space, the only way you can do this is to leave a width off the main content div entirely. There’s no way to know the value of 100 percent minus, say, 200 pixels. Without knowing this value, you have to leave a width off the main content div. And without a width, you can’t float the main content div and have to use margins to move it out of the way of the sidebar, which must be floating first in the source.

It actually is possible to create a hybrid layout where the main content comes first, using one of the negative margin techniques described later in this chapter. However, it’s a much more complicated layout method and not suitable for everyone. You may want to keep this simple sidebar-only floating method in your pocket for everyday use.

We’ll go over techniques for creating hybrid layouts in Chapter 6.


To stop the wrapping of the sidebar under the floated main content div and create a truly columnar look, add a margin to the side of the sidebar facing the float that is equal to or greater than the size of the float. In our case, that means we need a margin on the right that’s at least 75 percent (Figure 4.5):

#sidebar {
   margin-right: 75%;
   background: #FFA480;
}

Figure 4.5. The right margin on the sidebar moves it out from underneath the floated main content div to create two distinct, straight columns.


Note

The page showing this completed technique is liquid_margins_twocol.html in the ch4_examples.zip file.


Note

Don’t worry about the lack of spacing inside the columns right now—we’re just focusing on getting the columns in their proper places, not making them or their text look pretty. We’ll cover these typographical niceties in Chapter 7.


If you want a gap between the columns, you can increase the margin. For instance, a margin of 80 percent would create an implicit gap of 5 percent between the columns as well as decrease the implicit width of the sidebar to 20 percent (Figure 4.6):

#sidebar {
   margin-right: 80%;
   background: #E0D482;
}

Figure 4.6. A margin value that exceeds the width of the float creates a gap between the columns.


Adding a Third Column

You can use this same floats-and-matching-side-margins technique for creating three-column layouts, with a sidebar on either side of the main content div, but you’ll need to make one of the following two compromises to the purity of your (X)HTML:

  • Compromise the semantic purity by adding a wrapper div around the main content and secondary content (third column) divs.

    The div structure for this option would look like this:

    <div id="header"></div>
    <div id="content-wrapper">
    									<div id="content-main"></div>
    									<div id="content-secondary"></div>
    									</div>
    <div id="sidebar"></div>
    <div id="footer"></div>

    Rethinking the Two Flanking Sidebars

    If you need to have three columns, consider placing both of the sidebars on the same side instead of one on each side of the main content column, as you see most commonly done. Andy Rutledge argues against the usability shortcomings of the typical three-column layout in “Killing Some Bad Layout Conventions” at www.andyrutledge.com/bad-layout-conventions.php. Among the shortcomings that he lists are the tendency to overload the page with too much ancillary information as well as force the site visitors to learn where to look on the page for a particular sort of ancillary information, instead of grouping it all together in one place on the page.

    I’ll add poor source order to his arguments against the typical three-column layout. If you can put both sidebars on the same side, you should be able to keep the ideal source order of main content first, secondary content second—without any need for an extra wrapper div.


  • Compromise the ideal source order by placing both of the sidebar divs before the main content div in the source.

    The div structure for this option would look like this:

    <div id="header"></div>
    <div id="sidebar"></div>
    									<div id="content-secondary"></div>
    									<div id="content-main"></div>
    <div id="footer"></div>

I see the first option—the extra wrapper div—as less of a compromise. Although the extra div adds bulk to the (X)HTML for purely presentational purposes, it’s a very small addition, and in reality few pages get away with absolutely no presentational divs. That one extra div is not going to hurt anyone; keeping the main content first in the source, on the other hand, can have definite benefits.

Whenever possible, try to order the content in the (X)HTML source of the page in the most logical sequence. Pretend that you were reading the page out loud—what pieces of content would you read first? In general, you want to put your main content as close to the top of the page as possible. This is an immense benefit to users of screen readers, text browsers, and many handheld devices, as they will get to the most important content more quickly, without having to wade through repetitive navigation menus and sidebars on every page. It can also help you and your client, since content that comes earlier in the source is often weighted more heavily by search engines, and your main content is most likely to contain the keywords for which you’re optimizing each page.

Although good source order is important, it often comes at a cost of more complex CSS, and, as you can see in this case, can require extra divs. Let’s go over the simpler method first, which doesn’t involve the extra wrapper div but compromises the ideal source order.

Without the Extra Wrapper Div Once again, without the extra wrapper div you’ll need to put both sidebars before the main content in the (X)HTML:

<div id="header"></div>
<div id="sidebar"></div>
							<div id="content-secondary"></div>
							<div id="content-main"></div>
<div id="footer"></div>

You’ll then apply float: left to one sidebar and float: right to the other, along with their percentage widths:

#sidebar {
   float: left;
							width: 25%;
   background: #FFA480;
}
#content-secondary {
   float: right;
							width: 25%;
   background: #9BF598;
}

Next, get rid of the float and width we used earlier on the main content div. Instead, apply left and right margins to the div that match or exceed the widths of the sidebars (Figure 4.7):

#content-main {
   margin: 0 25%;
   background: #F0EE90;
}

Figure 4.7. With each of the sidebars floated to either side, the main content div simply takes up the remaining space in the middle.


Note

It doesn’t matter which sidebar div comes first in the source, nor whether the left float comes before the right float or vice versa.


You’ll want to keep the same CSS used earlier on the footer to make sure it doesn’t get overlapped by either of the sidebars above. The clear: both instead of clear: right declaration on the footer has come in handy, because there is now a left float as well as a right float above the footer. Without that clear: both, or if it was only a clear: right, the left-floated sidebar could overlap the footer.

Note

The page showing this completed technique is liquid_margins_threecol.html in the ch4_examples.zip file.


Now that we have a float on the left side of the page, the three-pixel text jog becomes visible. This is a bug present in IE 6 and earlier that adds three pixels of extra space between a float and the non-floated adjacent content—sometimes outside both columns and sometimes as a gap within the non-floated column on the side next to the floated column. It was actually also triggered in the two-column example, but was simply not noticeable because it happened along the inside right edge of the non-floated sidebar, where the ragged ends of the lines of text hid it. If we had floated the main content div to the left instead, the gap would have appeared inside the sidebar’s left side, promptly ending after the bottom of the main content div, creating a noticeable “text jog” (Figure 4.8). In this three-column version, you can see the text jog within the non-floated main content div. You may choose to ignore this, but it is also possible to add hacks to your page to get rid of it if you like (see the sidebar at right).

Figure 4.8. The text in the main content div is indented by three pixels along the full length of the sidebar div. As soon as the sidebar div ends, note how the text “jogs” back over three pixels to the left.


With the Extra Wrapper Div Adding a third column takes a little more work when you want the main content div to come first in the source. You can’t just add another div below the main content and float it—at least, not if you intend for the sidebars to flank either side of the main content column, instead of both sitting together on the main side. This is because when the main content div comes first and is floated, the browser will move it first as far to the right or the left as possible. Then the browser will move the next div, and then the next. But the main content div is already up against one of the sides of the viewport, with no space left over for the second sidebar to sit in.

The solution is to think of creating a three-column layout as creating two two-column layouts, one nested inside of the other.

Once again, here’s the div structure you’ll use:

<div id="header"></div>
<div id="content-wrapper">
							<div id="content-main"></div>
							<div id="content-secondary"></div>
							</div>
<div id="sidebar"></div>
<div id="footer"></div>

Hacking Away the Three-Pixel Text Jog

Although the three-pixel text jog is just a small cosmetic problem that will only be seen in a declining browser, you may want to add a hack to your page to get rid of it. Here’s what you do: assign side margins to the floats that are each three pixels smaller than you want the gap between the divs to be, set hasLayout (a made-up Microsoft DHTML property that cannot be turned on or off directly) on the non-float, and remove the side margins on the non-float. Here’s what those styles look like with our example:

<!--[if lte IE 6]>
<style>
#sidebar {
margin-right: -3px;
}
#content-secondary {
margin-left: -3px;
}
#content-main {
zoom: 1;
margin: 0;
}
</style>
<![endif]-->

Since we want the gap between the sidebars and the main content div to be zero, right and left margin values that are three pixels smaller than this, -3px, are used on each of the floated sidebar divs. The zoom: 1 on the content-main div is one hasLayout trigger that can be used. hasLayout is a made-up Microsoft DHTML property, present in IE 7 and earlier, that affects the layout of blocks in relation to each other and often determines whether certain IE bugs show up. It is either “on” or “off,” but it can’t be set to either of these values directly. Instead, you use other CSS properties, such as width, height, and zoom, to trigger hasLayout. For more information on hasLayout, see the comprehensive article “On Having Layout” by Ingo Chao (www.satzansatz.de/cssd/onhavinglayout.html).

These styles need to be hidden from all browsers except IE 6 and earlier. Here, the <!--[if lte IE 6]> line starts a conditional comment to do this. Conditional comments are special types of comments that only IE can read. Because they are truly just HTML comments, all other user agents ignore their contents, so they never see these hacks. You can customize the syntax to target all versions of IE or only particular ones; see http://msdn.microsoft.com/en-us/library/ms537512.aspx for examples. This conditional comment block needs to be placed below the existing closing style tag in the head of the page in order to override those earlier styles.


The first two-column layout is made up of the content-wrapper and sidebar divs, using the exact same two-column layout method we discussed at the start of the chapter:

#content-wrapper {
   float: right;
   width: 75%;
   background: #98F5E8;
}
#sidebar {
   margin-right: 75%;
   background: #FFA480;
}

Next, create another two-column layout within the content-wrapper div itself:

#content-main {
   float: left;
   width: 75%;
   background: #F0EE90;
}
#content-secondary {
   margin-left: 75%;
   background: #9BF598;
}

You may notice in Figure 4.9 that the sidebar divs don’t match in width, even though both should have explicit widths of 25 percent. This is because the 25 percent is calculated based on the parent element, and each sidebar has a different parent. The sidebar div’s parent is the body element, so it is going to be 25 percent as wide as the viewport. The content-secondary div, on the other hand, is nested within the content-wrapper div, which is only 75 percent as wide as the viewport. This means the content-secondary div is 25 percent of 75 percent, or roughly 19 percent of the viewport width.

Figure 4.9. The completed three-column layout using a wrapper div.


If your design depends on the two sidebars having identical widths, despite their differing points of reference for calculating those widths, you’ll need to resort to some algebra. Here’s the formula for figuring it out:

width of column you want to match ÷ width of parent column = width of nested column

So, if we divide 75 into 25, we get a result of .3333, or 33.33 percent. We’ll just round that to 33 percent, which means the width of content-main div needs to be 67 percent:

#content-main {
   float: left;
   width: 67%;
   background: #F0EE90;
}
#content-secondary {
   margin-left: 67%;
   background: #9BF598;
}

Note

The page showing this completed technique is liquid_margins_threecol_wrapper.html in the ch4_examples.zip file.


Figure 4.10. With the width of the nested content-main div decreased, the two sidebars now match in computed width.


Creating Columns by Floating Everything

Another way to create column layouts with CSS is to float every single div.

Note

We actually could float the sidebar to the right as well, and it would end up in the same space it now sits. That’s because float: right forces it to move as far to the right as it can, and the farthest to the right it can go is the left side of the main content column—right where it is now and where we want it.


Let’s go back to our simple two-column example, where the main content div was floated to the right. You’ll use the same CSS for the main content div, but remove the matching side margin from the sidebar div. You’ll then need to add float and width values to the sidebar div:

#content-main {
   float: right;
   width: 75%;
   background: #F0EE90;
}
#sidebar {
   float: left;
						width: 25%;
   background: #FFA480;
}

To make sure the footer doesn’t get overlapped by either of the columns above, keep using the same clear: both declaration that we’ve been using all along.

Note

The page showing this completed technique is named liquid_floats_twocol.html in the ch4_examples.zip file.


The two-column layout made by floating both of the columns looks exactly the same as if we had floated only one (as in Figure 4.5)—unless you look really closely or view the page at certain viewport widths in IE. All current browsers have some degree of trouble when you make widths of columns total exactly 100 percent, as our two columns do right now. Browsers have to translate every percentage dimension into a non-fractional number of pixels in order to display the page, which means they’re often forced to round to the nearest full pixel. If the browser rounds down, you might get a one-pixel-wide gap, and if it rounds up, you might get a one-pixel-wide overlap (Figure 4.11).

Figure 4.11. At certain viewport widths, rounded percentage measurements leave one-pixel-wide gaps between the columns.


In most designs, the one-pixel gap is neither noticeable nor detrimental to the design; it can often be worked around or—better still—ignored, if you, or your client, can tolerate that. The overlap is a bigger problem, simply because IE won’t let it happen. Instead, it decides that the divs don’t have room to sit side by side—since their combined width is the width of the viewport plus just one pixel—and it forces one to drop down beneath the other (Figure 4.12). This is often referred to as float drop. At certain window sizes the page will look perfectly fine, and at others it will appear that one column has completely disappeared.

Figure 4.12. At certain window sizes in IE, it might appear that the sidebar has disappeared completely (left). Not until you scroll down do you see that the sidebar is still there, but dropped below the level of the main content column (right).


To prevent that extra pixel from breaking the layout in IE, it’s best to choose dimensions that add up to a tiny bit less than 100 percent:

#content-main {
   float: right;
   width: 74.9%;
   background: #F0EE90;
}

This stops the float drop in IE, but makes the one-pixel gap show up even more often in all browsers. There are a few ways we can deal with it:

  • Ignore it. If you’ve created a design that doesn’t have to be “pixel perfect,” as I promoted in Chapter 1, that tiny gap shouldn’t be an issue for your design. For instance, you may choose not to have two solid blocks of color butted up against each other, as these sample layouts do. Even if you do have two differently colored columns touching each other, and you can’t have even one pixel of space between them, all might not be lost: You will probably end up using a “faux column” effect to create the colored columns out of a single background image anyway, and a single image of course can’t get gaps in it. We’ll cover the faux column technique in Chapter 8.

  • Move it to the outside by floating all the columns in the same direction. The gap will be less noticeable if it shows up on the outside edge of one of the columns, instead of between the two. You can make this happen by changing the float: left on the sidebar to float: right instead. It will move as far to the right as it can go—in this case, jammed up against the left side of the main content column, so not even a pixel can squeeze between the two. Any pixels of space left over from rounding problems will show up on the left side of the sidebar instead. A one-pixel gap on the very edge of the browser window is noticeable only in the most precise of designs.

  • Use a negative margin layout technique. Margins with negative values are not only allowed by the CSS specification, they’re quite useful. They can prevent you from having to declare widths on all your columns that add up to exactly 100 percent—the trigger for one-pixel gaps. Many negative margin layout techniques stop the gaps from occurring in standards-compliant browsers, but don’t do the same for IE. Later in the chapter, I’ll show you one that stops the gaps in all modern browsers. For now, let’s stick with the floating-all-the-columns methods, and we’ll come back to this alternative layout technique in a bit.

Of course, sometimes the anxiety over a one-pixel gap is moot, because we actually want a gap between the columns. To create a five-percent gap, as we did earlier in the chapter, we can simply reduce the width of either of the divs by five percent. This is safer than applying an actual margin value of five percent to the sides of one of the divs because it keeps the margin implicit instead of explicit. The gap will absorb any rounding inconsistencies the browser creates when calculating the explicit widths of the columns. It gives us breathing room.

Benefits of Floating All the Columns

So far it may seem like this floating-all-the-divs method is more trouble than the first layout method we discussed, where we floated only one column and used side margins to move the other over. However, there are some perks to this second method.

One advantage to this method is that we avoid the three-pixel text jog bug. It occurs only between floated and non-floated adjacent content, and since all our divs are now floated, it’s never triggered.

Another advantage is that each floated column creates a new block formatting context for itself. Basically, every block formatting context is an isolated container that controls the layout of the boxes within it, irrespective of any elements outside of it. It’s handy to have every column in your layout be in a separate block formatting context, because this allows you to use the clear property within one of the columns—to clear, say, a floated image in the text—without that clear also clearing a totally separate floated column. It makes the clear property ignore the external columns and affect only the layout within its own block formatting context.

It’s certainly possible to create a new block formatting context for each div using properties other than float, but not having to worry about setting some other CSS property just to get the clear property to work the way you want is a nice side effect of floating every single column. For more information on what block formatting context means and how it works, read “Control Block Formatting Context” at www.communitymx.com/abstract.cfm?cid=6BC9D.

Adding a Third Column

Creating a three-column layout when floating all the divs requires the same choice of compromise: do you prefer no extra divs or ideal source order?

If you want ideal source order and are thus comfortable adding that extra wrapper div, you’ll use the same idea of creating two two-column layouts, one nested inside of another, as we did earlier. But this time, you simply float every div, instead of using side margins on the non-floated divs to create room for the floats:

#content-wrapper {
   float: right;
   width: 75%;
   background: #98F5E8;
}
#content-main {
   float: left;
   width: 67%;
   background: #F0EE90;
}
#content-secondary {
   float: right;
							width: 33%;
   background: #9BF598;
}
#sidebar {
   float: left;
							width: 25%;
   background: #FFA480;
}
#footer {
   clear: both;
   background: #DDDDDD;
}

					  

Although the width of the content-wrapper div is only 75 percent, make sure the widths of the divs inside it—the content-main and content-secondary divs—add up to 100 percent (unless you want a gap between them, in which case you’d decrease one of their widths accordingly). Remember, percentage widths are always relative to the declared width of their parent elements. When we make the nested divs add up to 100 percent, we’re telling them to be 100 percent as wide as the content-wrapper div, not the viewport. If we change the width of the content-wrapper div, we don’t need to make any adjustments to its children divs—they’ll still fill up the whole width of the content div proportionally.

Note

The page showing this completed technique is liquid_floats_threecol_wrapper.html in the ch4_examples.zip file.


If you don’t want to have that extra wrapper div in your (X)HTML, or you don’t want to mess with algebra to get the two sidebars to match in width, you can reorder your source in one of two ways:

  • Order the divs sidebar, content-secondary, content-main. Float the sidebar div left and both content-secondary and content-main right.

  • Order the divs sidebar, content-main, content-secondary. Float all three either to the left (if you want the sidebar div on the left) or to the right (if you want it on the right).

Neither of these ordering options is ideal if the div we’re calling content-main is truly your most important content and ought to come first in the source (although the second option is a little better than the first). But this may not be the case. For instance, you may have three feature boxes you want to line up on your home page. In this case, it makes sense for the box that’s shown farthest to the left to be the first in the source, then the second leftmost box comes second in the source, and so on. The second ordering option, with all three divs floated to the left, would be ideal here.

Figure 4.13. On the Inmersio home page (www.inmersio.com), four columns are formed by floating each div to the left. The div farthest to the left is the first in the source, which is the most logical source order for this content.
Inmersio, www.inmersio, designed by Paulo Tromp


But neither of these reordering options is ideal when we’re dealing with the typical three-column layout for the page as a whole. That’s when our next three-column layout method comes in.

Creating Columns with Floats and Negative Margins

The two liquid layout methods we’ve looked at so far, using side margins beside floats and floating all the divs, each have their pros and cons. Negative margin layout techniques often avoid many of the cons of both: they provide ideal source order without the three-pixel text jog or the float drops that can happen in IE. Some negative margin techniques can also prevent the one-pixel gaps between columns that we’ve seen in standards-compliant browsers, and some even eliminate the need for extra wrapper divs, as we’ve used in our three-column methods.

However, negative margin techniques have their own unique downsides. They’re difficult to wrap your head around and can require some tricky math. Their increased complexity can lead to new problems in IE that we haven’t yet encountered, such as invisible or completely out-of-place columns. These IE bugs can be hacked, but adding hacks is yet another layer of complexity. You need to test negative margin layouts heavily in many different browsing scenarios to make sure they don’t fall apart.

There are a myriad of variations to negative margin layout techniques, but they all share some basic features:

  1. Space is created on the side or sides of the main content div using positive margin or padding values.

  2. The main content div is floated and given 100 percent of the remaining width.

  3. The sidebar or sidebars that follow the main content div in the source are pulled to the side by a negative margin, which effectively negates the space they would otherwise take up, allowing them to move up beside the main content div and preventing float drops.

It’s hard to explain in the abstract, so let’s walk through one type of negative margin layout so you can see in general how they work and decide if they might be right for your site. The steps for this technique are a little more involved than those for the previous layout methods we’ve gone through, so hang on tight.

Easier Negative Margin Techniques

The negative margin technique outlined here is actually a bit harder to grasp (though not really harder to implement) than some others out there. That’s because it’s a fully liquid layout, and fully liquid negative margin layouts tend to be more buggy, primarily in IE, than fixed-width or hybrid layouts. Most negative margin layout demos that you will find online use hybrid layouts, with fixed-width sidebars and a liquid middle column, which tends to fit very well with negative margin techniques. The tutorial “In Search of the Holy Grail” at www.alistapart.com/articles/holygrail showcases an excellent hybrid negative margin layout. It can be adapted to work with fully liquid layouts, but requires a little more tricky math, needs extra hacks added to get it to work in IE 6 and 7 (it doesn’t work at all in IE 5.x), and even then exhibits the one-pixel gap in IE (though not in other browsers). Still, it’s a great way to orient yourself to how negative margin layouts work, and perfectly suitable if you want hybrid instead of fully liquid.


Before working on the CSS for our negative margin layout, we need to add an extra wrapper div around the main content column in the HTML:

<div id="header"></div>
<div id="content-wrapper">
   <div id="content-main"></div>
</div>
<div id="content-secondary"></div>
<div id="sidebar"></div>
<div id="footer"></div>

This extra div is the main downside of this particular layout, but one that I consider quite minor given its accompanying strengths.

The wrapper div needs to be floated and assigned a width of 100 percent. The main content div within it will have space on either side of it, though, using margins set to the width of the sidebars:

#content-wrapper {
   float: left;
   width: 100%;
   background: #98F5E8;
}
#content-main {
   margin: 0 25%;
   background: #F0EE90;
}
#content-secondary {
   width: 25%;
   background: #9BF598;
}
#sidebar {
   width: 25%;
   background: #FFA480;
}

So far, the divs stack from top to bottom as normal (Figure 4.14). We can float the sidebars to either side, but that won’t get them to move up beside the main content div, since content-wrapper is taking up 100 percent of the available viewport width. That’s where the negative margins become necessary—they allow the divs to overlap, despite the lack of room, so they can sit on the same line with each other.

Figure 4.14. The main content div has space beside it for the two sidebars to sit in, but they are still sitting in their default positions below the main content div because they follow it in the source.


Let’s say we were to float the content-secondary div to the left, so it was sitting right up against the left side of the viewport. That’s exactly where it’s sitting even before being floated, but making it a float makes it want to move up beside the floated content-wrapper div if it can fit there. If we then give it a left margin value of 25 percent, it would push 25 percent to the right, or 25 percent away from the left side. If we give it a negative 25 percent margin instead, it simply does the opposite: it moves to the left, out of the visible area of the window, since it is only 25 percent wide itself. But, think of the viewport like Christopher Columbus did the Earth: it’s not flat, so if you go off one side, you come back on the other. When you push the content-secondary div off the left side of the viewport, it pops onto the right side of the viewport, overlapping the content-wrapper div (Figure 4.15). This happens only if it’s floated, however; without the float on both content-secondary and content-wrapper, they wouldn’t be able to sit on the same line. Floating on both divs is what gets content-secondary to move up, and the negative margin is what gets it to overlap content-wrapper:

#content-secondary {
   float: left;
   width: 25%;
   margin-left: -25%;
   background: #9BF598;
}

Figure 4.15. With the float and negative margin in place, the secondary content div can move up and overlap the content wrapper div. Since the main content has a gap to its right created by a margin, the overlap doesn’t actually cover any content, just the blue background color of the content wrapper div.


You need to do a similar thing for the sidebar div. Float it to the left, and it sits in the exact horizontal position that we want—it just needs space to be able to move up. We need to use a negative margin again to allow an overlap and create that space. We can’t use a value of 25 percent again, because that would put it right where content-secondary is, overlapping it. Instead, it needs to make one complete circuit behind the viewport and back to its original spot, so a value of negative 100 percent is what we need:

#sidebar {
   float: left;
   width: 25%;
   margin-left: -100%;
   background: #FFA480;
}

Note

If you use Adobe Dreamweaver to edit pages, you’ll find that it has an awful time trying to render negative margin layouts in Design View. This layout has its columns displaced, and the content of the two sidebars is completely uneditable in Design View. Unfortunately, there’s no fix—just submit it as a bug to Adobe at www.adobe.com/cfusion/mmform/index.cfm?name=wishform; hopefully they’ll get it fixed in the next release!


Figure 4.16. The float and negative margin on the sidebar div gets it to move up and overlap the content wrapper div, completing the layout of the three columns.


With all three columns in place, the only thing left to do is clear the footer, so that when one or both of the sidebar divs are longer than the main content div, they don’t overlap the footer. Unfortunately, the clear property alone isn’t enough to get IE 6 and earlier to stop the overlap of the content-secondary div over the footer completely, but adding position: relative to the footer—a common IE hack—fixes this without harming any other browsers:

#footer {
   position: relative;
						clear: both;
   background: #DDDDDD;
}

Problems with the Header Div in IE 6 and Earlier

We don’t have one in this example layout, but it’s very common to use a wrapper div around all the divs as a whole, from the header through the footer, usually as a vehicle for a background image or to limit the overall width of the layout. If you do add a wrapper div to this particular negative margin layout, you may find that your header div disappears in IE 6 and earlier. To fix this, add a hasLayout hack to the wrapper div like zoom: 1 or any width value.


And with that, our negative margin layout is complete. Although the logic behind the CSS can be difficult to understand at first, the amount of CSS used to create the layout is not really any greater than the other layout methods we’ve gone over, so once you understand how it works, it can be just as quick to create a negative margin layout as any other type.

Note

The page showing this completed technique is liquid_negative_threecol.html in the ch4_examples.zip file.


  • Creative Edge
  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint