There aren't many web developers who have not at least tried using Cascading Style Sheets (CSS) to define typography and simple page attributes such as background and text color. These days more and more developers are pushing CSS even further, eschewing tables and embracing CSS as a web page layout tool. In this article I'll explain why CSS is in many ways preferable to using tables for layout, and then I'll show you some CSS layout techniques using a complete re-coding of the Apple Internet Developer home page as an example.
This article assumes a familiarity with Cascading Style Sheets (CSS).
CSS layout uses style sheets to define the placement of elements on a web page. Typically CSS layout replaces tables, which are currently the most popular method of placing page elements. There is a common misconception that CSS layout techniques are incapable of producing complex page layouts. While it is true that tables generally provide more flexibility, I will show you that complex layouts are quite possible with CSS.
To get a quick look at the nuts and bolts of CSS layouts, take a look at the markup of a 3 column liquid page layout with a header, first done with tables, then with CSS.
This is the traditional method of web page layout, accomplished with a table. Notice that the content of the document (which is just dummy text) is interspersed with markup intended to define the content's visual presentation:
<html><head><title>Table layout</title></head><body bgcolor="white">
<table cellpadding="0" cellspacing="0" border="0">
<tr><td colspan="3" valign="top">
<font color="red" face="verdana, sans-serif">
A banner that sits at...top of the page.
</font>
</td></tr>
<tr><td width="190" valign="top">
<font color="green" face="verdana, sans-serif">
A column on ... left of the page.
</font>
</td>
<td valign="top">
<font color="blue" face="verdana, sans-serif">
A column in ... center of the page.
</font>
</td>
<td width="190" valign="top">
<font color="orange" face="verdana, sans-serif">
A column on ... right of the page.</font>
</td></tr></table>
</body></html>
Notice that this markup is relatively uncluttered because I've removed the visual layout instructions:
<html><head><title>CSS layout</title>
<style type="text/css">
@import url("threecolcss.css");
</style>
</head><body>
<div id="banner">
A banner that sits at ... top of the page.
</div>
<div id="rightcontent">
A column on ... right of the page.
</div>
<div id="leftcontent">
A column on ... left of the page.
</div>
<div id="centercontent">
A column in ... center of the page.
</div>
</body></html>
Of course you probably noticed the style element at the top of the markup which
specifies an external style sheet for the example: @import url("threecolcss.css");. The style
rules in that external document are as follows:
|
body {
font-family: verdana, sans-serif;
background:white;
}
#leftcontent {
color:green;
position: absolute;
left:10px;
width:190px;
}
#centercontent {
color:blue;
margin-left: 190px;
margin-right:190px;
}
#rightcontent {
color:orange;
position: absolute;
right:10px;
width:190px;
}
#banner {
color:red;
}
Now, if you're not using Internet Explorer 5+, Opera 5+, or a browser based on Mozilla, such as NS6+, then those two pages (table layout and CSS layout) probably look quite different. In fact, although the table layout page will look nearly identical in all browsers dating back to Netscape 1.1, only the most recent browsers (such as those listed in this paragraph) will properly display the CSS layout. According to recent browser usage stats, those most recent browsers make up of roughly 75% of the browsing audience.
|
Related Reading
Cascading Style Sheets: The Definitive Guide |
Make no mistake: pages laid out with CSS will NOT look the same in newer and older browsers. Beginning with 5th generation browsers (including the most excellent IE5/Mac, Netscape 6 on all platforms, and Opera 5) CSS support for layout reached an acceptable level. Nearly identical CSS layouts are possible in this browser set. Older browsers, including the tenacious NS4, and even the ahead-of-its-time IE4, are lacking in their support of even the CSS1 recommendation from 1996. Consequently, CSS layout is for the most part impossible in these browsers, with the exception of non-liquid, pixel-specific layouts such as those used in games.
But don't despair. As you will see, CSS pages are degradable, and CSS will create a useable page for any and all browsers. CSS layout will be used only by those browsers which support those features, but those using older browsers will still be able to see your content. What you give up in absolute control over layout in every browser you gain back in increased accessibility and more useful documents.
But given that roughly 25% of your site visitors will not be able to see your layout (although everyone will have access to your content), the natural question is "Why use CSS for layout?"
I've already mentioned a few of the negatives of CSS layout and hinted at some of the benefits. Let's take a look in more detail at the pros and cons of CSS layout. In the end, I think you'll agree with me that the benefits far outweigh the problems.
CSS allows you to separate the structure and presentation of documents. The separation of structure and presentation (often incorrectly referred to as the separation of style and content) is a principle that governs (or should govern) all markup languages, such as HTML. HTML is intended to structurally organize the content of a document so that it's clear what the conceptual relationship is between various portions of a document. The markup language is NOT intended to define the display of the document, although display and structure are often tightly connected.
|
Related articles: A Primer for Accessible Web Pages -- A look at the history of Section 508, which enforces accessibility for government web sites, followed by a discussion about how to prepare pages for those who cannot effectively use a graphical user interface. Modifying Styles -- Although browser support for Cascading Style Sheets has improved, modifying styles on the fly can still be painful at best. Fortunately, Steve Champeon provides a script to read and change an element's styles--regardless of where they were originally defined. DOCTYPE Explained -- The DOCTYPE element, in the head of your document, tells the browser what kind of HTML is used to describe the file. The better you match the DOCTYPE to your code, the more accurate your work will be rendered. Here's an introduction. Working with Fonts and CSS -- Changing fonts on web pages is anything but intuitive and easy. Fortunately, CSS can help. |
As web developers we have been trained to
see an <h1> tag as a way to make something bold
and large, not as a way of marking it as a section header. The
introduction of physical tags, such as <b>,
<i>, <font> and the abominable
<blink>, all of which specify display qualities
of document elements and not structural qualities, have only made
things more confusing for the developer. And this confusion is
unfortunately reinforced by the behavior of web browsers, which
apply styles to section headers and indeed make them large and bold.
But it is wrong to think that the markup is what specified the
style; in fact, the browser decides how to display a section header
according to internal logic given to it by its programmers. Had they
wanted, they might have specified that section headers be displayed
italicized, or with an underline. And that is where CSS comes in to
the picture. CSS allows you to override the browser's plans for
displaying any particular page element or group of elements.
The separation of structure and presentation results in the following benefits:
A semantic web: You may have heard of the semantic web before; it is a vision for the future of the internet where the millions and millions and documents available on the web are well-structured documents with markup that accurately describes their contents. In such a world, documents become much more accessible and understandable to computers, which makes it possible for computers to better act as a person's agent. For instance, search engines would function more effectively, as document indexers could take advantage of the markup of documents to organize results. More exciting possibilities include programmable bots which could scour the reaches of the web for the best price on buffalo milk mozzarella or for the latest interview with Britney Spears. If a document's markup describes the content, then computers are better able to understand the content.
Ease of redesign: Once we have removed layout instructions from the markup of our documents, redesign becomes a relatively simple task. Instead of cutting and pasting content out of tables, we simply write a new style sheet and apply it to our document. A whole site can be given a new look in seconds. Many sites already take advantage of this benefit of CSS layout, enabling site visitors to pick a "skin" for the site and applying different style sheets on the fly.
Degradable code: Some people feel that if you want cross-browser, backwards-compatible code, you have to use tables. Of course such thinking is a result of a fundamental misunderstanding of HTML, which as I've said is intended to carry structural information about a document. The most backwards-compatible (and forwards-compatible) code is that which is free from all bad HTML, such as physical tags and tables used for layout. These tags are nothing more than a wrench in the works, keeping more primitive devices such as text-only browsers and phone-based web interfaces from getting what they came for: the content.
Yes, by eschewing tables for layout and ridding your HTML of physical tags your page may not look as nice in NN4, but your content will be 100% accessible. Muck your pages up with tables and your site may look better in NN4, but you also interfere with other less capable browsers and internet devices from retrieving your content. In nearly all situations, I'll choose 100% accessibility. In some cases, of course, the design must win. Some content is only intended to be seen by 4+ browser users, and you could justify the use of table-based layout in such situations. In other situations it is worth the investment of time and money to create server-side solutions to provide content to devices with different capabilities. Doing so, you can feed table-based layouts to 4+ browsers, and feed clean and simple markup to older and less-capable devices, but most of us only want to maintain a single document, not a server application. Valid structural markup and CSS provide us with the opportunity to offer a single document that works in all Internet devices and has a complex page layout in the 5+ browser set.
|
To fully understand CSS layout, you must not only be aware of it's benefits, but you must also be ready for some problems it presents. Most of these problems stem out from CSS's immaturity. Yes, the recommendation itself has been around for a while, but CSS layouts are only recently possible, and even more recently taken seriously by developers. Expect this immaturity to result in problems, such as:
Layout limitations: The fact is that CSS layout will not currently allow you to do everything you can do with tables. This can be a real frustration, and has stopped many people from exploring what CSS can do. (I'll show you in this article that CSS can do quite a bit.)
Slight differences in browser display: CSS is difficult for browser makers to implement, and the W3C recommendations can be vague and confusing. So you can expect even the most recent browsers to behave differently when dealing with some aspects of CSS layout. Keep your layout simple enough and you will likely get a nearly identical display in Opera 5+, NS6, and IE5+. But as your layout increases in complexity, the odds that different browsers will render pages differently also increases.
Difficulty in switching from tables to CSS: For designers and developers accustomed to wrangling tables, using CSS for layout can be a confusing change. There is a "table mentality" that we developers have taken on over the years, and we are in large part unaware that it exists. Some take offense when this is pointed out, complaining instead that CSS is just difficult and non-intuitive. But if you were accustomed to driving a car with a steering wheel and you were then asked to head out on the freeway in a car steered with foot pedals, you certainly wouldn't be offended at the suggestion you had a "steering wheel mentality." The fact is, we are generally comfortable with tables. CSS layout is different, but we must not confuse differences with increased complexity.
So then, with all these problems, why use CSS? You'll have to make this decision yourself. Many people I know use CSS layouts for personal web projects, but still resort to tables when working on commercial sites. The time is coming when CSS will be suitable and preferred for all site layout, but many reasonably argue that the time has not yet arrived.
I use CSS because I believe in the fundamental principle of the separation of structure and presentation, and I am willing to put up with the problems CSS presents as I look forward to a time when CSS is as robust and simple to implement as tables are today. That time will come, and the web will be a better place for it.
To make things interesting, I took the Apple Internet Developer home page, which makes extensive use of tables, and I re-coded it using CSS for all layout. I've made a copy of the home page as it existed when I started this article, and I've turned on all table borders so you can see what we're working with: the Apple Internet Developer home page with table borders.
Now, If you're using IE5+ or NS6+, you should see virtually the same layout here: The Apple Internet Developer home page with only CSS. Opera 5+ users should see a very similar page, but with a few display quirks.
Now that I've shown you the fruits of my labor, take a closer look at the techniques used. Start at the top of the page, where there is a 600px wide graphical image bar centered in the browser window.
using a table this is accomplished something like so:
<center>
<table width="600"> ... </table>
</center>
The complete markup can be seen in the file top_nav_table.html.
Using CSS I got the same results by using a
DIV instead of a table element, and setting the DIV's margin attribute to the value auto, like so:
<style type="text/css">
#top_nav {
margin:auto;
width:600px;
}
</style>
<div id="top_nav"> ... </div>
Sadly, this is where I ran into the first
browser discrepancy. IE5.x does not properly implement the auto keyword, and so the DIV will not be
centered in that browser. Happily, there is a simple workaround: by
setting the text-align attribute of
the DIV's parent element (in this case, the body element), to center, I ensure that IE5.x will center the
DIV:
body {
text-align:center;
}
Those familiar with CSS may know that this
is a mis-implementation of the text-align attribute. But in this case, it
does provide a useful workaround.
Now take a look at all the style rules used in creating the top navigation bar using CSS (the complete markup can be seen in the file top_nav_css.html):
#top_nav {
margin:auto;
width:600px;
height:32px;
text-align:left;
}
I've already talked about the
margin and width attributes of the
#top_nav rule, the height attribute is
self-explanatory. The text-align:left attribute is
necessary because the text-align:center on the
body style rule will be inherited if this is not given.
Actually, you would think both of these latter attributes would be
unnecessary for this DIV, but removing them causes IE5 Mac to
incorrectly display the DIV. Better to leave them in.
#top_nav a {
display:block;
float:left;
}
This rule causes all the links in the
top_nav DIV to be treated as block elements instead of
using the default inline display value for anchor elements. You can
then float each of these elements left,
which is essentially the same as using the align
attribute of a block element or an IMG. This would normally not be
necessary, but notice that one part of the navigation bar is not an
image at all: it is a form. Once I floated all the
images left, which makes them align horizontally next
to one another, I inserted a form in this series of images (a form
with the id "MidSearch"), and applied the following style to it:
#MidSearch {
float:left;
margin:0px;
background-image:url("img/navbg.gif");
height:32px;
}
Notice that I used a background image for the form, which places an image behind the form's text element and makes it blend in nicely with the images in the navigation bar. The following rule defines the display of the form's input element:
#MidSearch input {
width:100px;
height:18px;
margin-top:4px;
}
And there you have it. I've replaced a double nested table structure with a simple series of links wrapped around images and a simple form. All the layout information has been moved into the style sheet. If you haven't already done it, now is the time to compare the markup code: using tables vs. using CSS
Next, take a look at the top middle section of the page, starting below the top navigation bar and ending at the first gray horizontal bar:
I won't spend any time on this code for this section because it uses the same CSS techniques as the top navigation bar.
|
Below the first gray bar, you'll find the meat of the page, a two-column section with numerous links to various onsite articles and offsite resources.
The basic two-column layout for this section
is created with three DIVs named main,
left, and right. I've given some DIVs
names that communicate their layout locations, which should help you
correlate the HTML elements with the style rules that govern them.
In real life, I would recommend giving your DIVs names that
communicate their contents, not their layout locations. The markup
looks something like this:
<div id="main">
<div id="left">
<img src="img/intro_descript.gif"
width="200" height="99" alt="..." name="Desc" id="Desc">
<div class="bodytitle">Related Links</div>
...
</div>
</div>
<div id="right">
<span class="bodytitle">Web Development & Mac OS X</span>
...
</div>
</div>
As you can see, the DIV main
contains two child DIVs, left and right.
The relevant styles look something like this:
#main {
margin:auto;
width:600px;
text-align:left;
}
#left {
float:left;
width:240px;
background-image:url("img/bar_back.jpg");
background-repeat:repeat-y;
}
#right {
width:330px;
margin-left:260px;
}
The style for the DIV main is
much like the style for the DIVs of the preceding section, all of
which define a 600px wide DIV centered in the middle of the page.
main's child DIVs are the two columns; left has a
float:right attribute, which allows right
to abut it on the right side, and both DIVs have widths set so that
they fit within the DIV main. right has a
margin-left attribute set at 260px to ensure that it
occupies the correct space within main.
To get the vertical gray bar along the left
side of the page, a background image is specified for the DIV
left, and the background-repeat attribute
is set to repeat-y, which causes the background image
to tile only vertically. And there you go.
In each of the two columns, there are
various CSS layout techniques used to create different lists, boxes,
and paragraphs. I'll describe a few of them. For instance, in the
left div all children DIVs are given a
left-margin of 25 with this rule:
#left div {
margin-left:25px;
}
Since all content in the left
div is contained within children DIVs, all content is given a
25px left margin, allowing space for the vertical gray
bar.
To create the box of links (pictured above), I nested a paragraph inside a DIV, like so:
<div id="links_div">
<p id="links_para" class="portallink">
<a href="...">CSS Compatibility Chart</a><br>
<a href="...">Apple's Business Case</a><br>
<a href="...">WebObjects</a><br>
<a href="...">QuickTime</a><br>
<a href="...">QuickTime Tutorials</a><br>
<a href="...">AirPort</a><br>
<a href="...">Apple.com</a><br>
<a href="...">The Apple Store</a>
</p>
</div>
I applied the following styles to those elements:
#left #links_div {
background-image:url("img/chains.gif");
width:201px;
height:191px;
margin-bottom:15px;
margin-top:-5px;
}
#left #links_div #links_para {
padding:46px 10px 0px 40px;
margin:0px;
}
The border and chains are all part of the
links_div background image, and the DIV's
height and width are set to the exact
dimension of that background image. Notice that the
top-margin of the DIV has a negative value, which
brings the "Related Links" and the links DIV a little closer
together. The nested paragraph element is then precisely placed
within the DIV by way of its border and
margin attribute values.
You'll notice my selectors, the part of a style rule that defines the page elements to which the rule applies, are failry verbose. Instead of the simple selector "#links_div", I use "#left #links_div". This labeling specifies that "#links_div" is a descendent, or is contained within, "#left". This practice is helpful when visually scanning my style sheets since it gives me more information about the part of my page that the style rules apply to.
The last section of the page I'll describe is the box at the top of the right-hand column:
Here is the relevant markup:
<div id="top_box">
<a id="top_box_image" href="http://developer.apple.com/macosx">
<img src="img/macosxbox.jpg" height="119"
width="100" alt="Mac OS X Box" border="0">
</a>
<div id="list_div">
<ul id="top_box_list">
<li><a href="...">Introduction</a>
<li><a href="...">Information Architecture</a>
<li><a href="...">Security Introduction</a>
<li><a href="...">Perl on Mac OS X</a>
<li><a href="...">PHP on Mac OS X</a>
<li><a href="...">Security: Mac OS X and UNIX</a>
<li><a href="...">Using mod_ssl</a>
<li><a href="...">Open Source Databases</a>
<li><a href="...">Java and Tomcat, Part I</a>
</ul>
</div>
<p class="bodytext">
<span class="bodytitle">Java and Tomcat</span><br>
With the introduction of the Unix-based Mac OS X, server-side Java...
</p>
</div>
The gray border of the box is created with
the border attribute of the DIV which contains the rest
of the content, like so:
#right #top_box {
border:1px solid gray;
padding:0px 12px 12px 12px;
}
I used the padding property of
the DIV to give the DIV's contents the proper amount of surrounding
white space, but notice that I did not assign a value to the
width property of the DIV. In general, assigning a
width and either padding or
margins to any box element will produce different
results in different browsers. This is because of a discrepancy in
IE 5.x PC's implementation of the box model, which is the cause of
most of the grief developers encounter when attempting their first
CSS layouts.
This issue has been expounded upon in
numerous other places on the web, and there are several solutions.
In this example, I solved the problem by stating the
padding but not declaring a width for the
DIV. The default behavior of a DIV without a specified
width is to simply fill the width of its parent
element. Since I defined a width (but not
padding or margins) for its parent DIV
(the DIV with id "right"), I got identical results in
all 5x browsers, even the broken IE5.x PC. This topic and other
common CSS problems are discussed in more detail here.
Now, within the DIV we have an image sitting to the left of a bulleted list, followed by a bit of text which fills the width of the DIV. The layout of the text requires no additional CSS, but the image and list use the following style rules:.
#right #top_box #top_box_image {
display:block;
float:left;
margin:40px 40px 0px 0px;
}
#right #top_box #list_div {
margin-bottom:10px;
float:left;
}
#right #top_box #list_div #top_box_list {
margin:0px;
padding:0px;
padding-top:10px;
}
The CSS above uses the float attribute to create the two-column effect in same manner as was used
for the two main content columns of the page. Before using the float
attribute, however, I had to make the img a block
element using the display attribute like so:
display:block. I also wrapped the ul
element in a DIV to work around discrepancies in how various
browsers handle floating the ul element. Then I set
float:left on BOTH the img and the DIV
element (technically I should only have to do that on the
img, but we do it to both to make sure all of our
target browsers align our img and DIV next to each
other as desired).
To get the nice aqua bullets for the list, I
used the list-style-image attribute, like
so:
#right #top_box #list_div #top_box_list li {
list-style-image:url("img/aquadot.jpg");
}
This replaces the browser's default bullets
with an image of our choosing. IE/PC may not display the bullets
properly, however, because of its idiosyncratic way of handling
margins around the ul element; but the
content does not suffer, and the layout suffers only minimally from
the lack of bullet images.
You're now ready to start using CSS instead of tables for your web page layout needs. As you experiment with the techniques discussed in this article, you'll find that creating CSS layouts is a learned skill, and that with practice it can become an easy task. If you're looking for more resources to guide you into the CSS sunset, try these:
Eric Costello is a contract developer for hire, working out of his mysterious company Schwa. He maintains a personal site at glish.com, where he links to articles on Web standards, DHTML, CSS, XML, and other topics of interest to web developers.
Return to the JavaScript and CSS DevCenter.
Copyright © 2007 O'Reilly Media, Inc.