spacer

Webref WebRef   Sitemap · Experts · Tools · Services · Newsletters · About i.com

home / web / authoring / style / sheets / layout / advanced


Developer News
MicrosoftÂ’s Automated Agent: Can We Talk?
Borland Finally Sells CodeGear
Red Hat Heads For The JON 2.0

Advanced CSS Layouts: Step by Step

By Rogelio Vizcaino Lizaola and Andy King (rojovizcaino@hotmail.com aking@internet.com)

Abstract

The Challenge: Replicate WebRef's front page using CSS. The Solution: CSS and lots of iterations.

Rogelio Lizaolo improves on Kwon Ekstrom's CSS version of WebRef's tabled home page. Months in the making, the final design successfully duplicates WebRef's layout without the use of tables. Numerous bugs were discovered in Netscape and Explorer in how they handle CSS, and we found some elegant workarounds to these and other problems. What follows is a step by step CSS layout tutorial that shows how we got to the final design.

Introduction

In Evolution of a Home Page Andy King threw down the gauntlet, challenging readers to duplicate WebRef's tabled (and fabled) home page in CSS. Kwon Ekstrom came up with a solution, that worked in a number of browsers. After investigating his solution, I found a few problems with his design, and thought I'd try and improve on it. Andy, Kwon, and I went back and forth over a number of months tweaking and improving my design. What follows is a step-by-step account of my attempt to duplicate WebRef's table-like layout using CSS, while avoiding some of the bugs and problems found in other implementations.

The ultimate goal is to create a CSS layout that exactly resembles the WebReference.com layout made with tables and also behaves well with small window sizes and large fonts.

The target browsers are all the generation five and greater browsers, for both Windows and Macintosh platforms. We are also looking to use the same style rules for all of these browsers. This constraint makes the task more difficult and the final code larger and more complex than it would be for a browser with good compliance to CSS level 2, like Netscape 6. Thus, we cannot use those features that aren't supported for all browsers and sometimes the necessary workarounds to solve bugs or other problems yield a not so straightforward use of CSS.

The Layout Challenge

WebRef Home PageThe WebReference home page circa Spring 2001 has six big blocks that hold and organize the content (using three main tables to lay out the page):

Can this complex layout be replicated using only CSS? Yes indeed! Read on to find out how. Disregarding the top navigation bar, the advertisement block and the "Tip of the day" we have a three column layout. We can ensure that the middle column is going to be the one with more content, and therefore, the height of the document will be dictated by this block, and the three columns should be the same size vertically. Notice that there is a white gap that separates the left column from the main content area and another one that does the same for the right column. These separators have the same width (9 pixels) as the margins around the table to the edge of the browser window.

3 Column Layout: Step by Step

To start, let's make a simple three column layout with gaps between the columns, with the center column content dictating the height of the entire document. We will start with four DIVs and their respective style declarations.

  1. First we set the margin and padding from the body element with the following code to give the desired appearance. Notice that we need to set the padding because Opera's default is not zero. Also, we set the background color to white, because Netscape 6 for the Macintosh defaults to a background color of gray.
    body {
        margin:9px 9px 0 9px;
        padding:0;
        background:#FFF;
    }
    
  2. Now we define our first element, a DIV that we will give an id attribute value to "level0." The only style definition for this element will be a background color, the color we want for the left column. Take a look
    #level0 {
         background:#FC0;
    }
    
  3. We nest a second DIV inside "level0" and give it the id "level1" thus.
    #level1 {
        margin-left:143px;
        padding-left:9px;
        background:#FFF;
    }
    
    This new DIV is going to make the space for the left column and left separator. The left column area will be reserved using a left margin for "level1" and the separator using a left padding, so we will need to set the background color from "level1" to the desired color for the separator. Take a look
  4. We nest inside "level1" a DIV with id "level2".
    #level2 {
        background:#FFF3AC;
    }
    
    We only change the background color of this new DIV. Now we can see clearly the left column and its separator. Take a look
  5. We use the same technique, nest a "level3" DIV inside "level2" to get the visual layout for the right column.
    #level3 {
        margin-right:143px;
        padding-right:9px;
        background:#FFF;
    }
    #main {
        background:#CCC;
    }
    
    This time we will nest another DIV called "main" just to set its background color different from transparent, and so we can highlight the columns and the separators. Take a look

Add the Top Nav and Ad Bars

We haven't made the code for the right and left columns content yet, just the visual layout, but we have illustrated the basic technique to display three columns and make them exactly the same height. So before discussing this issue let's put the top navigation bar and the advertisement block in place. We are going to nest inside "level1" and before "level2" a DIV with an id set to "topBar," and inside "topBar" we nest another DIV with an id set to "advBar." Take a look

...
#topBar {
    background:#FC0;
}
#advBar {
    background:#FFF3AC;
}
</style>
...
<body>
  <div id="level0">
    <div id="level1">
      <div id="topBar">
        This is the top navigation bar.
        <div id="advBar">
          This is the advertisement bar.
        </div>
      </div>
      <div id="level2">
        <div id="level3">
          <div id="main">
            The code you are reading.
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
...

Float the Tip-o-the-Day

We have at the moment three blocks where we can put some content, the main area, the top navigation bar and the advertisement block. Each one will be as high as its content demands, but we have constrained their widths so the blocks for the left and right navigation bars won't be invaded by the content in these DIV elements. Let's put in place the "Tip of the day" box using the float property so the content in the main area will flow around as needed. We put a DIV with id "tipDay" inside the "main" DIV, set the float property to right and declare its width to some value (be sure to declare the width for all the elements with float set to a value other than none). Take a look

#tipDay {
    float:right;
    width:175px;
    background:#FFF3AC;
}

Content Anyone?

Now let's tackle the problem on how to put content in those bars. The more natural way of doing it would be to use the float property, but due to Opera and IE's rendering problems with this technique we need to rely on absolute positioning to get things done. The IE bug is minimal, and could be disregarded but there is no way to solve the Opera bug that we discovered. Take a look at the links below for a description and example on this bugs. Buggy version on Opera, Float bug Opera, Float bug IE

Fill the Left and Right Nav Bars

Let's start with the left navigation bar by adding a DIV with its id set to "lftBar." Since we are going to use absolute positioning, we have more freedom to choose the place where the left bar chunk of source code goes. It could go inside "level0" before or after "level1" or even at the same nesting level as "level0" before or after, and this shouldn't make any difference if we choose the right reference frame and coordinates.

At least IE5.5 has a bug that causes overlap when we try to use "level0" as our reference and top and left set to zero for "lftBar" ("lftBar" being child of "level0" and "level0" with position property set to relative), so we have to use the body element as our reference frame and set the top and left property from "lftBar" to the same value used for the body margins. Take a look Buggy version on IE Another buggy version on IE

#lftBar {
    position:absolute;
    width:143px;
    top:9px;
    left:9px;
}

For the right navigation bar we will also use a DIV with its id set to "rgtBar." The first thing to notice, is that we should insert this new DIV in the proper place to make its top edge coincide with the "main" content area's top edge. So we insert it inside "level2" before or after "level3," set "level2" position property to relative to use it as our reference frame and for "rgtBar" we set position to absolute, top and right to zero and its width to the same value we used for the right margin of "level3." Take a look

#level2 {
    background:#FFF3AC;
    position:relative;
}
...
#rgtBar {
    position:absolute;
    width:143px;
    top:0;
    right:0;
}

Visibility and Position Fixes

This version has two problems in IE for Windows. The first one is that the "Tip of the day" box disappears, although the content in the main keeps flowing as if it were still there. This rendering problem has an easy solution, we set the position property of "tipDay" to relative and we get back the proper rendering. Setting the position to relative forces the z-index higher for the tipDay DIV, pushing it to the front.

A Strange Inheritance: Width "Auto" vs. "Inherit"

The second problem for windows IE is that the right navigation bar horizontal position is off, as far right as possible. To solve this problem we have to give "level2" (the reference for "rgtBar") a width declaration. IE doesn't understand the keyword 'auto' for this property but understands 'inherit' in a particular way (not standard) and we can exploit this on our behalf. We set "level0" width to 100% and "level2" width to inherit, the trick is that IE will inherit the value from "level0" and the rest of the browsers will inherit the value 'auto' from "level1" (the default). If we declare the width directly to 100% for "level2" we still have rendering problems (IE 5.5+ sets 100% width TABLES to the width of the entire browser window, thus we set width 100% only on level0). Note that you can also use the CSS parsing error IE5 bug to fix this and similar problems, see the workarounds section below for details. Take a look

#level0 {
    background:#FC0;
    width:100%; # - New, outermost DIV
}
#level2 {
    background:#FFF3AC;
    position:relative;
    width:inherit; # - New, inherits 100% from level0 in IE5
                   #        inherits auto from level1 in all others
}
#tipDay{
    float:right;
    width:175px;
    background:#FFF3AC;
    position:relative; # - New, forces z-index so this div displays in IE
}

Clean Some Style

It's time to do some cleaning and place other elements that will point to problems that have to be worked out. First we will get rid of "level3" and pass all its style declaration to "main." This next example has a left border for the right navigation bar using the border-right property from "main" (remember that "level3" no longer exists). We add two headers to the main and some sample content and also some headers to the right bar with some style rules. At the bottom of the right bar we have placed "A_Long_String" header to show problems with large font sizes. The text inside this element can't be broken into different lines, so it will overflow if its width exceeds the width set to the right bar. Go ahead and test it with different font sizes. Take a look

#main { # Where the main content goes
    margin-right:143px;
    padding-right:9px;
    background:#FFF;
}
#main h1 { # Where our main section headers go
    margin:0;
    padding-left:.3em;
    font:1.25em Verdana,Helvetica,Arial;
    color:#609;
    background:#FC0;
}
#main dt { # Bump up the main content links
    font-weight:bold;
    font-size:120%;
    margin-top:.8em
}
#rgtBar h3 { # Subheads for right nav bar, (newsletter, experts...) 
    margin:0;
    padding:3px;
    background:#FC0;
    font-weight:bold;
    font-size:1em;
    text-align:center;
}

Fixed vs. Relative Sizes

To prevent this overflow problem we will change some style declarations from "rgtBar" and "main" to a value expressed in relative units as "em." We have been using a fixed 143 pixels. That would be about 9ems with the browser font size set to 12 points. One handy equivalency is 12pt = 16px. So we change now the values for width and margin-right from "rgtBar" and "main" respectively to 9em instead of 143px. By using a relative measure we have a right bar that changes its width proportionally to the user's desired font size value. Try it with large font sizes. Take a look

#main {
    margin-right:9em; # - Use variable widths rather than fixed, they are
                          more user-friendly. This also applies to font sizes.
    padding-right:9px;
    background:#FFF;}
...
#rgtBar {
    position:absolute;
    width:9em; # - likewise
    top:0;
    right:0;
}

Depending on the browser the user has different ways to set the desired font size. The technique described above solves overflow problems for most of the possible user interactions but not all. We set now the "Tip of the day" box width in the same way but stick to absolute units for the left navigation bar, since it doesn't have overflow problems that break the layout.

Float the Search Form

Now we are going to place the search form and text links into the top navigation bar. To insert the form we just give it a float right treatment and write the chunk of code as the first child of "topBar." We have to declare a width for this element since we are floating it, 10.5 em is a good value and note that we are using em units to let the input elements grow according to the browser selected font size. We also set the text alignment to right, since the form is a little wider than the space used by the input elements. We aren't done yet, so try it to see what we're going to solve next. Take a look

#topBar form {
    float:right;
    width:10.5em;
    text-align:right;
}    

We need to set the form's margins to zero to make the form's vertical size as small as possible. For Netscape we have to add a line-height of .7em to make the search button height the same size as the other input element, this statement doesn't change anything for IE or Opera. The float overlaps part of the advertisement block. We can't allow this because we are going to have a text link just below the search form but inside the advertisement block, so we set "advBar" clear property to right. Finally we set "topBar" width to 100% to solve an IE bug that breaks the layout and declare that the input elements in the top bar have a font size of .8em, this way they will grow proportionately accordingly to the browser's font size. Take a look

#advBar {
    background:#FFF3AC;
    clear:right; # - New, clear the search form
}
...
#topBar form { # The search form
    float:right;
    width:10.5em;
    text-align:right;
    margin:0;
    line-height:.7em; # - Crucial!
}
#topBar input {
    font-size:.8em;
}

Add Some Text Links

Now let's put the text links in place. There are five text links separated by bullets and wrapped by a BOLD ("b") element, so this b element should be the second child of "topBar". Now, there is a strange bug in Windows IE 5.0 that flushes these links to the right. To deal with this problem we can wrap the b element with a DIV element and set its text alignment property to left or we can use the display property from the b element to convert it into a block element and then set the text alignment to left. We also set the font style and chose a good value for the line height so the text links are vertically centered. Take a look

#topBar b { # Top nav bar text links (sitemap, experts...)
    display:block;
    text-align:left;
    font:bold .8em/1.7em Arial,Geneva,sans-serif;
}

Add Real Content, and Float a Tip Title

In this step we are going to change the headers 'This is the main.' and 'This is the main2.' to 'WebReference.com: Dev the Web™' and 'internet.com' respectivly, as this is the real content in the WebReference site. We are doing this because we are going to put a title to the "Tip of the day" box, and this title goes in the same dark colored header bar that holds the 'WebReference: Dev the Web™' text. To accomplish this we are going to use a DIV element identified by "tipTit," this element should be the first child of "main" and have its float property set to right, again we need to set its width to some value and give it some font style attributes to have it vertically centered. The width used is 7em (the same width of "tipDay") and we also set text-align to right and the position property to relative, this solves a rendering problem in IE that we discussed before. The line-height property should be set to the same value used in the header to give the vertical centering. Take a look

#tipTit {
    float:right;
    width:7em;
    text-align:right;
    position:relative;
    font:.8em/1.8em Arial,Geneva,sans-serif;
    background:red;
}
.note {
    color:red
}

That's it! We've successfully replicate WebReference.com's front page layout using CSS. Now let's and add an ad and change the Tip of the Day title to the proper background color. Take a look Note: The final version has not yet been tested in IE6. We'll address this browser in a future update.

#advBar p{text-align:right;margin:0 0.5em;font-weight:bold;}
#advBar img{margin-bottom:1em}

[In the mean time, many readers have written to inform us that there are at least some problems with IE6 in this layout. The worst offender appears to be that the background color in the right column automatically realigns with the right edge of the window when you reduce the window size (which is correct) however the actual content of the right column remains right aligned with the edge of the banner ad (which is ugly). Thus, as you continue to reduce the size of the page, the content stops when it hits the width of the banner ad, but the background color continues to be moved to the left. Sigh.... -Ed.]

Future Improvements

This tutorial should give you a better idea of how to create simple to complex multi-column layouts using just CSS. To further refine the design we could also add in the lighter colored news/highlight items in the left column, and beef up the padding so it matches (like tipDay, though we'd use a surrounding DIV here, see workarounds below). For the two table-like left/right rows ([sitemap | experts .... search] and [WebReference: Dev the Web .... Tip of the Day]) we can explore using A List Apart's technique of float left/right 49% width around a spacer DIV, although the form might pose a challenge. We'll need to test it for compatibility with our target browsers of course. We could further optimize our CSS, but the version now uses no tricky implied if/then parsing error tricks in the CSS as before so it could be used for a production site. Let us know what you think of these techniques, and feel free to try improving it yourself. Here's a summary of what we learned along the way.

Summary of CSS Workarounds

Be fluid
Use relative lengths where possible (em or % for fonts, em for DIV widths)
Nest your DIVs
This is a workaround to solve boxing model differences, so it's a powerful crossbrowser technique. Padding and borders and widths don't mix well in IE5. Make sure you separate your style settings of padding and borders from any width settings in DIVs. IE5x for the PC's box implementation incorrectly puts the padding and border of a box within its stated width. The W3C says that padding and border are to be added to the width, and IE5 Mac and Gecko-based browsers correctly implement the box model. Instead, if you've got to set the width of a box, that also needs padding or borders, separate them into two divs, not one. The rule is: For the same block element you might set horizontal margins and width or horizontal margins, horizontal borders and horizontal padding. Avoid declaring width and padding or width and borders for the same block element. Use nesting to achieve the desired visual.
Don't use "nowrap" for DIVs
Netscape and Opera will overflow these at larger font sizes.
IE 5.x has a CSS parsing error that can be used
IN IE5x comments are interpreted as code rather than ignored, so this can be utilized to do crude if/thens to workaround bugs in IE5x. IE 6 eliminates this error. We used this technique to set the right bar's width etc. before coming up with the above inherit workaround:
#fontChanger {font-size:.8em;//font-size:1em;}
Watch your DIV and table widths
Setting WIDTH:100% in a DIV can cause it to not match the width of DIVs set to auto (the default) in IE and, in IE5.5 when using table width="100%" IE assumes entire window width, not the DIV width, so you can use //width:100% in a surrounding DIV and width:inherit in a table's style sheet.
#topBar{background:#FC0;//width:100%;}
#topBar form{display:inline;}
table.c{font:.8em/1em Arial,Geneva,sans-serif;width:100%;//width:inherit;}
IE doesn't inherit as it should, our guess is that it will inherit the value from the last ancestor that has a declared width value (absolute and relative values or 'inherited' keyword, IE doesn't support 'auto' keyword). The percentages are calculated based on the inherited value so the above rules for percentage values also applies.
Floats can cause clearance problems
Especially with forms. Solutions: use a DIV around the enclosing DIV set to clear to avoid this in NS6 or set the form line height to less than the DIV's height and clear the DIV below. The technique used in the article from A List Apart is also an alternative solution.
Do not use fixed heights
Version 5/6 browsers do not support them. Also min-height is not supported, in v5/6 browsers. IE 5.5 doesn't support min-width, max-width, min-height, max-height.
In forms, set margin:0 for Opera and Netscape
Especially for floats, to minimize margins like IE.
If you want to use bottom or right properties you have to set either the width or height for the parent and it will work in IE.
Opera conflicts more with the W3C's CSS specification, so you need to set the width for the child if you want to use the right property, if you want to use the bottom property you have to set the height for both parent and child. This explains some positioning problems we had in the right bar for IE. This works if the parent doesn't have margins. Opera and IE 5.5 have systematic errors when margins are present on the parent.

Further Reading

About the Authors

Rogelio Vizcaino Lizaola is 23 years old, born and raised in Mexico City. He's currently studying Physics at the U.N.A.M. (Universidad Nacional Autónoma de México). With a programming background, Rogelio started to code some simple programs in QBasic for physics and math-related problems. Then he started to learn some C, C++ and Delphi programming. He's self taught in HTML and has discovered the wonders of CSS from the W3C. He can be reached at rojovizcaino@hotmail.com.

Andrew B. King is an unspecified age and has been working on the Web since time immemorial. He's got a couple of engineering degrees from the University of Michigan, with plenty of programming thrown in for good measure. He founded WebReference.com in 1995 and JavaScript.com in 1999 and managed both until recently cutting back to newsletter editor for these two internet.com publications. He still occasionally updates or creates new tutorials if he finds an inspiring reason or topic. He can be reached at aking@internet.com.

Acknowledgements

Thanks to Kwon Ekstrom (justice@softhome.net) for coming up with the original CSS layout, and helping out with this version. Thanks to Andy King for his help in refining our design and hammering all our iterations mercilessly on his Mac.



JupiterOnlineMedia

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info


Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

Solutions
Whitepapers and eBooks
Microsoft Article: HyperV-The Killer Feature in WinServer ‘08
Avaya Article: How to Feed Data into the Avaya Event Processor
Microsoft Article: Install What You Need with Win Server ‘08
HP eBook: Putting the Green into IT
Whitepaper: HP Integrated Citrix XenServer for HP ProLiant Servers
Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 1
Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 2--The Future of Concurrency
Avaya Article: Setting Up a SIP A/S Development Environment
IBM Article: How Cool Is Your Data Center?
Microsoft Article: Managing Virtual Machines with Microsoft System Center
HP eBook: Storage Networking , Part 1
Microsoft Article: Solving Data Center Complexity with Microsoft System Center Configuration Manager 2007
MORE WHITEPAPERS, EBOOKS, AND ARTICLES
Webcasts
Intel Video: Are Multi-core Processors Here to Stay?
On-Demand Webcast: Five Virtualization Trends to Watch
HP Video: Page Cost Calculator
Intel Video: APIs for Parallel Programming
HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
Microsoft Silverlight Video: Creating Fading Controls with Expression Design and Expression Blend 2
MORE WEBCASTS, PODCASTS, AND VIDEOS
Downloads and eKits
Sun Download: Solaris 8 Migration Assistant
Sybase Download: SQL Anywhere Developer Edition
Red Gate Download: SQL Backup Pro and free DBA Best Practices eBook
Red Gate Download: SQL Compare Pro 6
Iron Speed Designer Application Generator
MORE DOWNLOADS, EKITS, AND FREE TRIALS
Tutorials and Demos
How-to-Article: Preparing for Hyper-Threading Technology and Dual Core Technology
eTouch PDF: Conquering the Tyranny of E-Mail and Word Processors
IBM Article: Collaborating in the High-Performance Workplace
HP Demo: StorageWorks EVA4400
Microsoft How-to Article: Get Going with Silverlight and Windows Live
MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES
webref The latest from WebReference.com Browse >
Perl Pragma Primer · Implement Drag and Drop in Your Web Apps: Part 2 · How to Create an Ajax Autocomplete Text Field: Part 5
Sitemap · Experts · Tools · Services · Email a Colleague · Contact FREE Newsletters 
 The latest from internet.com
SQL Server 2005 Express Edition - Part 22 - Upgrading from Microsoft SQL Server Desktop Engine (MSDE) · Vyatta: Downgrades that Pay Off · NetMotion Brings Cross-Network Support to Wireless VoIP

 


Revised: Aug. 28, 2001

URL: http://webreference.com/authoring/style/sheets/layout/advanced/