CSS CHAPTER 4 2018-12-19T12:24:43+00:00

CSS CHAPTER 4

Topics:- (Planning your layout, Setting the foundations, Float-based layouts, Fixed-width, liquid, and elastic layout, Liquid layouts, Elastic layouts, Liquid and elastic images, Faux columns, Equal-height columns, CSS 3 columns, CSS Frameworks vs. CSS Systems, Bug hunting, Having layout, Workarounds, Common bugs and their fixes, Graded browser support)

Layout

One of the major benefits of CSS is the ability to control page layout without needing to use presentational markup. However, CSS layout has gained an undeserved reputation for being difficult, particularly among those new to the language. This is partly due to browser inconsistencies, but mostly due to a proliferation of different layout techniques available on the Web. It seems that each CSS author has their own preferred way of creating multicolumn layouts, and new CSS developers will often use a technique without really understanding how it works. This situation has been exacerbated by the rise of so-called CSS frameworks, which aim to make CSS layout easier by creating a strong coupling between markup and presentation—the very reason we ditched table-based layout in the first place. This black box approach to CSS may get quick results but ultimately stunts the developer’s understanding of the language and ability to implement changes. All these CSS layout techniques rely on three basic concepts: positioning, floating, and margin manipulation. The different techniques really aren’t that different, and if you understand the core concepts, it is relatively easy to create your own layouts with little or no hassle. In fact, layout is generally the easiest part of CSS; it’s all the tweaking that takes time.

In this chapter, you will learn about

Horizontally centering a design on a page

Creating two- and three-column float-based layouts

Creating fixed-width, liquid, and elastic layouts

Creating equal height columns

CSS frameworks versus CSS systems

How to track down CSS bugs

The mysterious hasLayout property

Hacks and filters

The most common browser bugs and their fixes

Graded browser support

Planning your layout

When it’s time to start turning your designs into fully functional templates, it is very tempting to jump straight in and start marking up your page or slicing up your images. However, you can find that you’ve painted yourself into a corner very quickly. Instead, a small amount of planning can save a lot of hassle further down the line. Or, as the saying goes, “Measure twice; cut once.”

The first step in creating a scalable and easy to maintain CSS system is to review your designs, looking for repeating patterns. These could be patterns in the structure of the page or the way certain elements are repeated across the site. You shouldn’t be too concerned with the visual representation at this stage. Instead, look at the structure and meaning. We can do this by printing out each design, spotting the patterns and then scribbling mark-up notes on each page (see Figure 4-1). However, many people do this by annotating their Photoshop files or grey-box designs.

Figure 4-1. Markup guides

Begin by breaking your pages into major the structural areas like the wrapper, header, content area, and footer. These areas tend to be consistent across the whole site and rarely change. To use an architectural analogy, you could think of these as the external walls of the building. Then, turn your attention to the content area itself, and start building out your grid structure. How many different content areas does the design have, and how do they differ? Are the content areas actually that different, or can they be treated the same from a layout perspective? Most designs will have only a couple of unique content areas, so look for shared characteristics rather than the visual representation. You could consider these content areas as the internal load-bearing walls of your construction.

Finally, we need to start looking at the different layout constructs that appear in the various content areas. Do you need to present certain types of information in two, three, or four columns? Unlike the previous step, these layout constructs tend to be very flexible and change from page to page. So you could think of them like the dry wall partitions in your building. Combined with the previous step, these construct help form the floor plan of each of your pages. At this point, reach for the graph paper and colored pencils, and start mapping the structure and dimensions in more detail (see Figure 4-2).

Figure 4-2. Working out dimensions on graph paper

With the structure in place, you can now turn your attention to the different kinds of content. Is this is a news story, an article, or a press release? Give each block a meaningful name and then see how they relate to each other. It may turn out that there’s actually very little difference between your news stories and press releases, in which case, combining them into a single content type would make sense. Look at how each content block is structured, and see if you can see patterns emerging across different types. For instance, you may notice that both your articles and news stories have a prominent header and footer, so identify them as such. It really doesn’t matter if the headers and footers look different, as you can style them later based on context. The same is true of things like error messages, search boxes, and menu items. Try to keep the class names as generic as possible, and style them based on context.

Once we’ve got patterns and naming conventions sorted, it’s useful to start defining the elements we are going to use. For example, a list of links might be an unordered list, while a story might to be a div with an h2, a paragraph, and an anchor element. It’s much easier to do this up front, with a few of your colleagues, than on the fly. It’s useful to jot down color codes, dimensions, and anything else that will help during production. Again, you can make these annotations on a printout of the designs for quick reference, as shown in Figure 4-3.

Figure 4-3. Working out the details of the different content types

Setting the foundations

Let’s assume that we’re going to be building a classic three-column blog template, like the one shown in Figure 4-4.

Figure 4-4. Classic, three-column layout

By analyzing the design, it’s clear that we’re going to need a wrapper element to center the design, along with a header, content area, and footer. The markup would, therefore, look something like this:

<body>

<div class=”wrapper”>

<div class=”header”>

<!–Your header content goes here–>

</div>

<div class=”content>

<!–Your page content goes here–>

</div>

<div class=”footer”>

<!–Your footer content goes here–>

</div>

</div>

</body>

As these last three areas are enclosed inside the wrapper, let’s start by styling the wrapper element.

Centering a design using margins

Long lines of text can be difficult and unpleasant to read. As modern monitors continue to grow in size, the issue of screen readability is becoming increasingly important. One way designers have attempted to tackle this problem is by centering their designs. Rather than spanning the full width of the screen, centered designs span only a portion of the screen, creating shorter and easier-to-read line lengths. Say you have a typical layout where you wish to center a wrapper div horizontally on the screen:

<body>

<div class=”wrapper”>

</div>

</body>

To do this, you simply define the width of your wrapper div and set the horizontal margins to auto:

.wrapper {

width: 920px;

margin: 0 auto;

}

In this example, we decided to fix the width of my wrapper div in pixels, so that it fits nicely on an 1024×768–resolution screen. However, you could just as easily set the width as a percentage of the body or relative to the size of the text using ems. This works on all modern browsers. However, IE 5.x and IE 6 in quirks mode don’t honor the margin:auto declaration. Luckily, IE misunderstands text-align: center, centering everything instead of just the text. You can use this to your advantage by centering everything in the body tag, including the wrapper div, and realigning the contents of the wrapper back to the left:

body {

text-align: center;

}

.wrapper {

width: 920px;

margin: 0 auto;

text-align: left;

}

Using the text-align property in this way is a hack—but a fairly innocuous hack that has no adverse effect on your site. The wrapper now appears centered in older versions of IE as well as more standards-compliant browsers (see Figure 4-5).

Figure 4-5. Centering a design using margin:auto

Float-based layouts

There are a few different ways of doing CSS-based layout, including absolute positioning and using negative margins.Float-based layouts the easiest and most reliable method to use. As the name suggests, in a float-based layout, you simply set the width of the elements you want to position and then float them left or right. Because floated elements don’t take up any space in the flow of the document, they no longer appear to exert any influence on the surrounding block boxes. To get around this, you will need to clear the floats at various points throughout the layout. Rather than continuously floating and clearing elements, it is quite common to float nearly everything and then clear once or twice at strategic points throughout the document, such as the page footer. Alternatively, you could use the overflow method to clear the contents of particular elements. This is my current preferred method, so it’s the one I’ll be using throughout the rest of these examples.

Two-column floated layout

To create a two-column layout inside our content area, we first need to create our basic HTML structure.

<div class=”content”>

<div class=”primary”>

<!– main content goes here –>

</div>

<div class=”secondary”>

<!–navigation and secondary content goes here –> </div>

</div>

The secondary content area for this design—including the site navigation—will be on the left side of the page, while the primary content will be on the right. However, we have chosen to put the primary content area above the secondary content area in the source order for usability and accessibility reasons. First, the primary content is the most important thing on the page and so should come first in the document. Second, there is no point forcing screen reader users to trawl through navigation links and less important content like site promotions before they get to the primary content if they don’t have to. Normally, when people create float-based layouts, they float both columns left and then create a gutter between the columns using margin or padding. When using this approach, the columns are packed tightly into the available space with no room to breathe. Although this wouldn’t be a problem if browsers behaved themselves, buggy browsers can cause tightly packed layouts to break, forcing columns to drop below each other.

This can happen on IE because it honors the size of an element’s content, rather than the size of the element itself. In standards-compliant browsers, if the content of an element gets too large, it will simply flow out of the box. However, on IE, if the content of an element becomes too big, the whole element expands. This can be triggered by the smallest things, such as some of your text being set in italic. If this happens in very tightly packed layouts, there is no longer enough room for the elements to sit next to each other, and one of the floats will drop. Other IE bugs, such as the 3-pixel text jog bug and the double-margin float bug, along with various browser-rounding errors can also cause float dropping.To prevent your layouts from breaking, you need to avoid cramming floated layouts into their containing elements. Rather than using horizontal margin or padding to create gutters, you can create a virtual gutter by floating one element left and one element right (see Figure 4-6). If one element inadvertently increases in size by a few pixels, rather than immediately running out of horizontal space and dropping down, it will simply grow into the virtual gutter.

Figure 4-6. Creating a two-column layout using floats

The CSS for achieving this layout is very straightforward. You simply set the desired width of each column and then float the secondary content left and the primary content right. You also need to add a small amount of padding to the primary content to prevent the enclosed text being flush to the right hand edge of the element. You’ll notice that we’ve also added display:inline to all the floated items. This is a defensive measure to prevent the double margin float bug in IE.

.content .primary {

width: 650px;

padding-right: 20px;

float: right;

display: inline;

}

.content .secondary {

width: 230px;

float: left;

display: inline;

}

As the total width available is 920 pixels, these dimensions leave a 20-pixel wide virtual gutter between each floated element. As mentioned previously, doing this protects the layout from float drops due to accidental content expansion. Because these elements are floated, they no longer take up any space in the flow of the document, causing the footer to rise up. In order to prevent this, you need to clear the floated items by applying the overflow method to their parent element, in this case the content div.

.content {

overflow: hidden;

}

And there you have it: a simple two-column CSS layout (see Figure 4-7).

Figure 4-7.Floated two-column layout

You’ll notice that rather than creating two separate elements called primary-content and secondary-content, I’ve simply used the terms primary and secondary. We’ve then used the fact that these two elements are nested within the content element to create the association. This has a couple of benefits. First off, it means that you don’t have to keep creating new class names for every element you want to style. Instead, you can use the cascade to help you out. Secondly, and arguably more importantly, you can use the same primary and secondary classes more than once, creating a very flexible naming system. For instance, say we wanted to create a three-column layout instead of just a two-column one.

Three-column floated layout

The HTML needed to create a three-column layout is very similar to that used by the two-column layout, the only difference being the addition of two new divs inside the primary content div: one for the main content and one for the secondary content. Therefore, we can reuse our flexible primary and secondary class names again.

<div class=”content”>

<div class=”primary”>

<div class=”primary”>

<– your primary primary content goes here –> </div>

<div class=”secondary”>

<– your secondary primary content goes here –> </div>

</div>

<div class=”secondary”>

<!–navigation and secondary content goes here –> </div>

</div>

Using the same CSS as the two-column technique, you can float the secondary content left and the primary content right. Then, inside the primary content div, you can float the primary div left and the secondary div right (see Figure 4-8). This essentially divides the primary content area in two, creating a three-column effect.

Figure 4-8. Creating a three-column layout by dividing the content column into two columns

As before, the CSS for this is very simple. You just set your desired widths and then float the primary div left and the secondary div right, creating a 20-pixel gap in the middle:

.content .primary .primary {

width: 400px;

float: left;

display: inline;

}

.content .primary .secondary {

width: 230px;

float: right;

display: inline;

}

One thing you’ll notice is that the right-hand padding we gave to the primary div in the in the first example is now being applied to our new primary div in the second example. As such, we need to remove the pading from the more general style and apply it to the more specific style.

.content .primary {

width: 670px; /* width increased and padding removed*/

float: right;

display: inline;

}

.content .secondary {

width: 230px;

float: left;

display: inline;

}

.content .primary .primary {

width: 400px;

float: left;

display: inline;

}

.content .primary .secondary {

width: 230px;

padding-right: 20px; /* padding applied here instead*/

float: right;

display: inline;

}

This leaves you with a nice and solid three-column layout (see Figure 4-9).

Figure 4-9. Three-column layout using floats

Fixed-width, liquid, and elastic layout

So far, all the examples have used widths defined in pixels. This type of layout is known as fixed-width layout. Fixed-width layouts are very common, as they give the developer more control over layout and positioning. If you set the width of your design to be 960 pixels wide, it will always be 960 pixels. If you then want a branding image spanning the top of your design, you know it needs to be 960 pixels wide to fit. Knowing the exact width of each element allows you to lay them out precisely and know where everything will be. This makes fixed-width layout the easiest and therefore most common approach.

However, fixed-width designs have their downsides. First, because they are fixed, they are always the same size no matter what your window size. As such, they don’t make good use of the available space. On large screen resolutions, designs created for 1024×760 can appear tiny and lost in the middle of the screen. Conversely, a design created for a 1024×760 screen will cause horizontal scrolling (or crawling) on smaller screen resolutions. With an increasingly diverse range of screen sizes to contend with, fixed-width designs don’t adapt well to the flexible nature of the Web. As such, they often feel like a poor compromise. Another issue with fixed-width design revolves around line lengths and text legibility. Fixed-width layouts usually work well with the browser default text size. However, you only have to increase the text size a couple of steps before sidebars start running out of space and the line lengths get too short to comfortably read. To work around these issues, you could choose to use liquid or elastic layout instead of fixed-width layout.

Liquid layouts

With liquid layouts, dimensions are set using percentages instead of pixels. This allows liquid layouts to scale in relation to the browser window. As the browser window gets bigger, the columns get wider. Conversely, as the window gets smaller, the columns will reduce in width. Liquid layouts make for very efficient use of space, and the best liquid layouts aren’t even noticeable. However, liquid layouts are not without their own problems. At small window widths, line lengths can get incredibly narrow and difficult to read. This is especially true in multicolumn layouts. As such, it may be worth adding a min-width in pixels or ems to prevent the layout from becoming too narrow. However, set the min-width too large and your liquid designs inherit the same constraints as their fixed-width cousins. Conversely, if the design spans the entire width of the browser window, line lengths can become long and difficult to read. You can do a couple of things to help avoid this problem. First, rather than spanning the whole width, you could make the wrapper span just a percentage—say, 85 percent. You could also consider setting the internal padding and margins as percentages as well. That way, the padding and margins will increase in width in relation to the window size, stopping the columns from getting too wide, too quickly. Last, you should add a maximum width on the wrapper to prevent the content from getting ridiculously wide on oversized monitors.

You can use these techniques to turn the previous fixed-width, three-column layout into a fluid, three-column layout. Start by setting the width of the wrapper as a percentage of the overall width of the window. Most people will pick an arbitrary size based on what looks good on their screens, and that’s perfectly fine. However if you want to be more precise, take a look at your browser stats to calculate the most common window size and then pick a wrapper percentage that matches how the fixed width version would look at that size. A good tool for this is Liquid Fold (http://liquidfold.net/). For example, if your designer used a width of 960 pixels and the majority of your users have their browser windows set to 1250 pixels, the percentage to use would be (960 ÷ 1250) × 100 = 76.8 percent. Next, set the width of the primary and secondary content areas as a percentage of the wrapper width. In the previous example, the width of our primary content div was 670 pixels. As the total width was 920 pixels, this works out as 72.82 percent. Similarly, the width of the secondary content div works out at exactly 25 percent. This leaves a 2.18 percent virtual gutter between the navigation and the wrapper to deal with any rounding errors and width irregularities that may occur:

.wrapper {

width: 76.8%;

margin: 0 auto;

text-align: left;

}

.content .primary {

width: 72.82%;

float: right;

display: inline;

}

.content .secondary {

width: 25%;

float: left;

display: inline;

}

You then need to set the widths of the columns inside the primary content area. This gets a bit trickier, because the widths of the content divs are based on the width of the primary content element and not the overall wrapper. So this time, the width of the primary div is 400 pixels, which works out to be 59.7 percent of the parent element. Similarly, the width of the secondary div works out to be 34.33 percent. Finally, we still need a 20-pixel gutter, which works out at 2.63 percent of the parent element.

.content .primary .primary {

width: 59.7%;

float: left;

display: inline;

}

.content .primary .secondary {

width: 34.33%;

padding-right: 2.63%;

float: right;

display: inline;

}

This produces a liquid layout that is optimal at window size of 1250 pixels but is comfortable to read at both larger and smaller screen resolutions (see Figure 4-10).

Figure 4-10. Three-column liquid layout at 800×600, 1024×768, and 1250×900

Because this layout scales so nicely, there isn’t any need to add a max-width property. However, to ensure the lines of text remain a readable length, it’s always a good idea to add a max-width in ems. The layout does start to get a little cramped at smaller window sizes, so I’m going also to add a min-width in ems as well.

.wrapper {

width: 76.8%;

margin: 0 auto;

text-align: left;

max-width: 125em;

min-width: 62em;

}

And there you have it, a nice, flexible, liquid layout.

Elastic layouts

While liquid layouts are useful for making the most of the available space, line lengths can still get uncomfortably long on high-resolution monitors. Conversely, lines can become very short and fragmented in narrow windows or when the text size is increased a couple of steps. If these limitations are of concern, elastic layouts may be your solution. Elastic layouts work by setting the width of elements relative to the size of the font instead of the width of the browser. By setting widths in ems, you ensure that when the font size is increased the whole layout scales. This allows you to keep line lengths to a readable size and is particularly useful for people with reduced vision or cognitive disorders.

Like other layout techniques, elastic layouts are not without their issues. Elastic layouts share some of the problems with fixed-width layouts, such as not making the most use of the available space. Also, because the whole layout increases when the text size is increased, elastic layouts can become much wider than the browser window, forcing the appearance of horizontal scroll bars. To combat this, it may be worth adding a max-width of 100% to the wrapper div; max-width wasn’t supported by IE6 and below, but it is supported by newer versions. If you need to support max-width in IE 6, you can use JavaScript as well. Elastic layouts are much easier to create than liquid layouts as all of the HTML elements essentially stay in the same place relative to each other; they just all increase in size. Turning a fixed-width layout into an elastic layout is a relatively simple task. The trick is to set the base font size so that 1 em roughly equals 10 pixels.The default font size on most browsers is 16 pixels. Ten pixels works out at 62.5 percent of 16 pixels, so setting the font size on the body to 62.5% does the trick:

body {

font-size: 62.5%;

text-align: center;

}

Because 1 em now equals 10 pixels at the default font size, we can convert our fixed-width layout into an elastic layout relatively easily.By keeping the internal widths as percentages and only setting the wrapper width in ems, the internal widths will still size themselves relative to the font size. This allows you to change the overall size of the layout without having to change the width on each individual element, making for a more flexible and maintainable solution.

.wrapper {

width: 92em;

max-width: 95%;

margin: 0 auto;

text-align: left;

}

.content .primary {

width: 72.82%;

float: right;

display: inline;

}

.content .secondary {

width: 25%;

float: left;

display: inline;

}

.content .primary .primary {

width: 59.7%;

float: left;

display: inline;

}

.content .primary .secondary {

width: 34.33%;

padding-right: 2em;

float: right;

display: inline;

}

This produces a layout that looks identical to the fixed-width layout at regular text sizes (see Figure 4-11), but scales beautifully as the text size is increased (see Figure 4-12).

Figure 4-11. Elastic layout at the default text size

Figure 4-12. Elastic layout after the text size has been increased a few times

With the increasing prevalence of page zooming in modern browsers, some people have begun to question the need for elastic layouts. However, until all browsers support page zooming by default, you may still want to consider elastic layouts for older browsers.

Liquid and elastic images

If you choose to use a liquid or an elastic layout, fixed-width images can have a drastic effect on your design. When the width of the layout is reduced, images will shift in relation to it and may interact negatively with each other. Images will create natural minimum widths, preventing some elements from reducing in size. Other images will break out of their containing elements, wreaking havoc on finely tuned designs. Increasing the width of the layout can also have dramatic consequences, creating unwanted gaps and unbalancing designs. But never fear—there are a few ways to avoid such problems. For images that need to span a wide area, such as those found in the site header or branding areas, consider using a background image rather than an image element. As the branding element scales, more or less of the background image will be revealed:

#branding {

height: 171px;

background: url(/img/branding.png) no-repeat left top;

}

<div id=”branding”></div>

If the image needs to be on the page as an image element, try setting the width of the container element to 100% and the overflow property to hidden. The image will be clipped on the right-hand side so that it fits inside the branding element but will scale as the layout scales:

#branding {

width: 100%;

overflow: hidden;

}

<div id=”branding”>

<img src=”/img/branding.png” width=”1600″ height=”171″ /> </div>

For regular content images, you will probably want them to scale vertically as well as horizontally to avoid clipping. You can do this by adding an image element to the page without any stated dimensions. You then set the percentage width of the image, and add a max-width the same size as the image to prevent pixelization. For example, say you wanted to create a news story style with a narrow image column on the left and a larger text column on the right. The image needs to be roughly a quarter of the width of the containing box, with the text taking up the rest of the space. You can do this by simply setting the width of the image to 25% and then setting the max-width to be the size of the image, in this case 200 pixels wide:

.news img {

width: 25%;

max-width: 200px;

float: left;

display: inline;

padding: 2%;

}

.news p {

width: 68%;

float: right;

display: inline;

padding: 2% 2% 2% 0;

}

As the news element expands or contracts, the image and paragraphs will also expand or contract, maintaining their visual balance (see Figure 4-13). However, on standards-compliant browsers, the image will never get larger than its actual size.

Figure 4-13. Giving images a percentage width allows them to scale nicely in relation to their surroundings

Faux columns

You may have noticed that the navigation and secondary content areas on all these layouts have been given a light gray background. Ideally, the background would stretch the full height of the layout, creating a column effect. However, because the navigation and secondary content areas don’t span the full height, neither do their backgrounds. To create the column effect, you can make fake columns by applying a repeating background image to an element that does span the full height of the layout, such as a wrapper div. Dan Cederholm coined the term “faux column” to describe this technique. Starting with the fixed-width, two-column layout, you can simply apply a vertically repeating background image, the same width as the navigation area, to the wrapper element (see Figure 4-14):

#wrapper {

background: #fff url(/img/nav-bg-fixed.gif) repeat-y left top;

}

Figure 4-14. Faux fixed-width column

For the three-column fixed width layout, you can use a similar approach. This time, however, your repeating background image needs to span the whole width of the wrapper and include both columns (see Figure 4-15). Applying this image in the same way as before creates a lovely faux two-column effect (see Figure 4-16).

Figure 4-15. Background image used to create the faux three-column effect

Figure 4-16. Faux three-column effect

Creating faux columns for fixed-width designs is relatively easy, as you always know the sizes of the columns and their positions. Creating faux columns for fluid layouts is a little more complicated; the columns change shape and position as the browser window is scaled. The trick to fluid faux columns lies in the use of percentages to position the background image. If you set a background position using pixels, the top-left corner of the image is positioned from the top-left corner of the element by the specified number of pixels. With percentage positioning, it is the corresponding point on the image that gets positioned. So if you set a vertical and horizontal position of 20 percent, you are actually positioning a point 20 percent from the top left of the image, 20 percent from the top left of the parent element (see Figure 4-17).

Figure 4-17. When positioning using percentages, the corresponding position on the image is used

Positioning background images using percentages can be very useful, as it allows you to create background images with the same horizontal proportions as your layout and then position them where you want the columns to appear. To create a faux column for the secondary content area, you start by creating a very wide background image. In this example, We have created an image that is 4000 pixels wide and 5 pixels high. Next, you need to create an area on the background image to act as the faux column. The secondary content area has been set to be 25 percent of the width of the wrapper, so you need to create a corresponding area on the background image that is 25 percent wide. For a background image that is 4000 pixels wide, the faux column part of the image needs to be 1000 pixels wide. Output this image as a GIF, making sure that the area not covered by the faux column is transparent.

The right edge of the faux column is now 25 percent from the left side of the image. The right edge of the secondary content area is 25 percent from the left edge of the wrapper element. That means if you apply the image as a background to the wrapper element, and set the horizontal position to be 25 percent, the right edge of the faux column will line up perfectly with the right edge of the navigation element.

.wrapper {

background: #fff url(/img/secondary-faux-column.gif) repeat-y 25% 0;

}

You can create the background for the primary content area using a similar method. The left edge of this faux column should start 72.82 percent from the left edge of the image, matching the position of the primary content element relative to the wrapper. Because the wrapper element already has a background image applied to it, you will need to add a second wrapper element inside the first. You can then apply your second faux column background image to this new wrapper element.

.inner-wrapper {

background: url(/img/primary-faux-column.gif) repeat-y 72.82% 0;

}

If you have worked out your proportions correctly, you should be left with a beautiful three-column liquid layout with columns that stretch the height of the wrapper (see Figure 4-18).

Figure 4-18. Faux three-column layout

Equal-height columns

As well as creating columns as part of your main layout, you may want to create equal-height columns elsewhere in your design, like the ones in Figure 4-19. While this is easy to accomplish using tables, it’s a little trickier in CSS.

Figure 4-19. Three, equal-height columns

Let’s start with the mark-up.

<div class=”wrapper”>

<div class=”box”>

<h1>Andy Budd</h1>

<p>…</p>

<div class=”bottom”></div>

</div>

<div class=”box”>

<h1>Richard Rutter</h1>

<p>…</p>

<div class=”bottom”></div>

</div>

<div class=”box”>

<h1>Jeremy Keith</h1>

<p>…</p>

<div class=”bottom”></div>

</div>

</div>

For this example, you are going to need three divs, one for each of the three columns. Inside each div, you’ll need a heading, some copy, and an empty div to use as a hook for the bottom corners. All three divs are then enclosed in a wrapper div, which we will use to constrain the height. We can now start styling our boxes.

.wrapper {

width: 100%;

}

.box {

width: 250px;

margin-left: 20px;

float: left;

display: inline;

padding: 20px;

background: #89ac10 url(/img/top.gif) no-repeat left top;

}

You will see from Figure 4-20 that this leaves us with three, uneven columns.

Figure 4-20. The three columns before the main technique being applied

The trick to this technique is to give each box a large amount of bottom padding and then remove this height with a similar amount of negative margin. This causes each column to overflow the wrapper element (see Figure 4-21). If you then set the overflow property of the wrapper to hidden, the columns get clipped at their tallest point. In this example, I’m giving each element a bottom padding of 520 pixels and a bottom margin of 500 pixels. The 20 pixels difference forms the visible padding at the bottom of each box.

.wrapper {

width: 100%;

overflow: hidden;

}

.box {

width: 250px;

padding-left: 20px;

padding-right: 20px;

padding-top: 20px;

padding-bottom: 520px;

margin-bottom: 500px;

margin-left: 20px;

float: left;

display: inline;

background: url(/img/top.gif) #89ac10 top left no-repeat;

}

Figure 4-21. The red border shows the bounds of the wrapper div, so you can see how the three colums flow out of this element

To position the bottom of the columns in the right place, you need to align them with the bottom of the wrapper element. To do this, you first need to set the positioning context by giving the wrapper a position of relative. You can then set to position of the empty divs to be absolute and set their bottom properties to be zero. Now, all you need to do is give the elements the correct width and height and apply the bottom image as a background.

.wrapper {

width: 100%;

overflow: hidden;

position: relative;

}

.box {

width: 250px;

padding-left: 20px;

padding-right: 20px;

padding-top: 20px;

padding-bottom: 520px;

margin-bottom: 500px;

margin-left: 20px;

float: left;

display: inline;

padding: 20px;

background: url(/img/top.gif) #89ac10 top left no-repeat;

}

.bottom {

position: absolute;

bottom: 0;

height: 20px;

width: 290px;

background: url(/img/bottom.gif) #89ac10 bottom left no-repeat;

margin-left: -20px;

}

The result is a three-column layout that retains the height of the longest column, as shown in Figure 4-19. Neat, huh?

CSS 3 columns

CSS 3 also gives us the ability to create equal-height text columns, as shown in Figure 4-22. This is achieved through the column-count ,column-width and column-gap properties.

Figure 4-22. Text columns using the CSS 3 column properties

Say you start with the following markup:

<h1>Socrates</h1>

<div class=”col”>

<p>After philosophizing for a while…</p>

</div>

Applying these rules will create a three-column layout where each column is 14 ems wide and has a 2-em gap between it and the next columns. One of the nice features of CSS columns is what happens if the available space becomes smaller than the width of the defined columns. Rather than the columns wrapping, as you’d get if you were using floats, the column count simply reduces. So if there weren’t enough space for three columns, you would reduce down to two.

.col {

-moz-column-count: 3;

-moz-column-width: 14em;

-moz-column-gap: 2em;

-moz-column-rule: 1px solid #ccc;

-webkit-column-count: 3;

-webkit-column-width: 14em;

-webkit-column-gap: 2em;

-webkit-column-rule: 1px solid #ccc;

column-count: 3;

column-width: 14em;

column-gap: 2em;

column-rule: 1px solid #ccc;

}

As you can probably see from the preceding code, CSS columns aren’t widely supported yet. As such, you need to back up the regular code with the use of browser-specific extensions.

CSS Frameworks vs. CSS Systems

In the programming world, frameworks like Rails or Django take common patterns in web development, such as adding records to a database, and abstract them into a simple set of reusable components. This abstraction allows developers to build fairly sophisticated applications without needing to engineer these functions from scratch. Unlike a library of stand-alone functions, frameworks tend to be highly integrated. As such, frameworks are abstracted to such a degree that it’s possible, although not desirable, to build entire applications without needing to understand the parent language. Over the last couple of years, we’ve slowly seen the rise of so-called CSS frameworks. These frameworks aim to take some of the drudgery out CSS and help users create a variety of common layouts without needing to edit the underlying CSS. Instead, these frameworks encourage developers to use a series of markup patterns and naming conventions and then manage the layout behind the scenes. The three most popular frameworks are YUI Grids, Blueprint, and 960 (see Figure 4-23), although there are several others to choose from.

Figure 4-23. The YUI, Blueprint, and 960 web sites

These frameworks offer a number of useful productivity benefits including global style resets, sitewide typographical handling, and consistent form treatment—things you will need on the majority of your projects. However, frameworks also change the way you write your markup, losing the important separation of presentation from meaning. For instance, the markup used in the Blueprint framework is clearly presentational in nature, talking, as it does, in terms of columns and column spans.

<div class=”column span-24″>

<!– header –>

</div>

<div class=”column span-4″>

<!– left sidebar –>

</div>

<div class=”column span-16″>

<!– main content –>

</div>

<div class=”column span-4 last”>

<!– right sidebar –>

</div>

By using frameworks to control layout, developers are forced to use a presentational style of markup that more closely resembles table-based design. In fact, you could argue that tables are better than CSS frameworks, because tables have the same ridged, presentational mark-up without the extra CSS to download. Frameworks also force the developer to learn not only the underlying language but the framework as well. Often this doesn’t happen, and the developer is left with a partial understanding of both. Frameworks have another disadvantaged in the fact that they enforce a specific grid structure on your designs. This is fine if your designs happen to fit the widths and margins defined by the framework. However, just as it’s unacceptable for your programming framework to dictate the user experience of your website, it’s unacceptable for your CSS framework to dictate the design of your site. By selecting a specific framework, the danger is that you’ll end up using it for every project and thus painting yourself into a corner. Or, as the saying goes, if you only have a hammer, everything looks like a nail.

These problems become evident when you understand where frameworks came from. Rather than being designed from scratch as a flexible layout system for any possible design, most were created for the use on specific sites like Yahoo or the Laurence Kansas Journal. These sites already had well-defined grid structures and style guides, so the developers knew that every new page would follow the same pattern. Over time, the developers found other uses for these systems, so they abstracted them and released them to the general public. However, the focus of these frameworks on their original sites is still evident in their design. So how do we get the productivity benefits from CSS frameworks without the obvious disadvantages? This is where the concept of CSS systems comes in. A CSS system is essentially a toolbox of reusable styles and markup patterns that can be used to develop site-specific frameworks. This toolbox could include your global resets, typographic styles, and form treatments, along with markup patterns for common HTML widgets such as sign-up forms, calendar tables, and navigation lists. You can then use the techniques you’ve learned  to develop a system for your clients that acts like a customized framework, complete with all the different layout options they will need. This process initially involves a little more work on the your part, but it provides all the benefits of a CSS framework without the pitfalls.

Bugs and Bug Fixing

Compared to many programming languages, CSS is a relatively simple language to learn. The syntax is straightforward, and due to its presentational nature, there is no complicated logic to grapple with. The difficulties start when it comes time to test your code on different browsers. Browser bugs and inconsistent rendering are major stumbling blocks for most CSS developers. Your designs look fine on one browser, but your layout inexplicably breaks on another. The misconception that CSS is difficult comes not from the language itself, but the hoops you need to jump through to get your sites working in older browsers. Bugs are difficult to find information on, poorly documented, and often misunderstood. Hacks are seen by many as magic bullets—arcane sigils with exotic names that, when applied to your code, will magically fix your broken layouts. Hacks are definitely potent tools in your armory, but they need to be applied with care and generally as a last resort. A much more important skill is the ability to track, isolate, and identify bugs. Only once you know what a bug is can you look for ways to squash it.

Bug hunting

We all know that browsers are buggy, some of them more than others. When a CSS developer comes across a problem with code, there is the immediate temptation to mark it as a browser bug and look for a hack or workaround. However, browser bugs aren’t as common as everybody likes to think. The most common CSS problems arise not from the browser bugs but from an incomplete understanding of the CSS specification. To avoid these problems, it is always best to approach a CSS bug assuming that you have done something wrong. Only once you are sure that there are no errors on your part should you consider the problem to be the result of a browser bug.

Common CSS problems

Some of the simplest CSS problems are caused by typographical and syntactical errors in your code. Things like forgetting to end your declarations with a semi-colon or typing font-face when you meant font-family. A simple way to get round this problem is to choose a CSS editor like SKEdit or CSS Edit that includes syntax highlighting and code completing. These features will help prevent basic errors but are no substitute for proper validation. Running your code through a service like the CSS Validator (http://jigsaw.w3.org/css-validator/) will highlight any grammatical errors, showing you the lines the issues are on and a brief description of each error (see Figure 4-25).

Figure 4-25. The Microsoft website as seen through the eyes of the CSS Validator

The Firefox Web Developer Toolbar extension (https://addons.mozilla.org/en-US/firefox/addon/60) includes shortcuts to the online versions of both the HTML and CSS validators. There is also the popular HTML Validator for Firefox (http://users.skynet.be/ mgueury/mozilla/When validating your HTML and CSS, you may be greeted with a page full of errors. This can be quite intimidating at first, but don’t worry. Most of these errors will be the result of one or two actual errors. If you fix the first error mentioned and revalidate, you will see many of the original errors disappear. Do this a couple of times, and your code should quickly become error free. Remember that the validator is only an automated tool and is not infallible. There are a growing number of reported bugs with the validator, so if you think something is right but the validator is saying something different, always check against the latest CSS specification. For instance, at the time of this writing, the CSS validator was still throwing up errors for vendor-specific extensions like —moz-border-radius, even though these are allowed in the CSS specification. If in doubt, validate your code using the CSS 3 profile and then check the specification if you’re unsure of anything.

Problems with specificity and sort order

As well as syntactic errors, one of the more common problems revolves around specificity and sort order. Specificity problems usually manifest themselves when you apply a rule to an element, only to find it not having any effect. You can apply other rules and they work fine, but certain rules just don’t seem to work. In these situations, the problem is usually that you have already defined rules for this element elsewhere in your document using a more specific selector. In the following example, CSS developers have set the background color of all the paragraphs in the content area to be white. However, they want the introductory paragraph to be orange and so have applied that rule directly to the paragraph:

.content p {

background-color: white;

}

.intro {

background-color: orange;

}

If you test this code in a browser, you will see that the introductory paragraph is still white. This is because the selector targeting all the paragraphs in the content area is more specific than the selector targeting the introductory paragraph. To achieve the desired result, you need to make the selector targeting the introductory paragraph more specific. In this case, the best way to achieve this is to add the class for the content element to the start of the intro paragraph selector:

.content p {

background-color: white;

}

.content .intro {

background-color: orange;

}

Try not to add more-specific selectors without thinking, as you may cause specificity issues is other parts of your code. Instead, it is often better to remove extraneous selectors, making them as generic as possible, and only add more specific selectors when you need fine-grain control.The Firebug add-on for Firefox (https://addons.mozilla.org/en-US/firefox/addon/1843) is an invaluable tool for debugging your CSS. One of its many useful features is the ability to inspect an element to see which CSS styles are being overridden. It does this by crossing out any styles that are being overridden elsewhere in the style sheet, as shown in Figure 4-26.

Figure 4-26. Styles appear crossed out when they are overriden in other parts of the stylesheet

Problems with margin collapsing

Margin collapsing  is another CSS feature that, if misunderstood, can cause a lot of gray hairs. Take the simple example of a paragraph nested inside a div element:

<div id=”box”>

<p>This paragraph has a 20px margin.</p>

</div>

The box div is given a 10-pixel margin and the paragraph is given a 20-pixel margin:

#box {

margin: 10px;

background-color:#d5d5d5;

}

p{

margin: 20px;

background-color:#6699FF;

}

You would naturally expect the resulting style to look like Figure 4-27, with a 20-pixel margin between the paragraph and the div, and a 10-pixel margin around the outside of the div.

Figure 4-27. This is how you would expect the preceding style to look

However, the resulting style actually looks like Figure 4-28.

Figure 4-28. This is how the style actually looks

Two things are going on here. First, the paragraph’s 20-pixel top and bottom margins collapse with the 10-pixel margin on the div, forming a single 20-pixel vertical margin. Second, rather than being enclosed by the div, the margins appear to protrude from the top and bottom of the div. This happens because of the way elements with block-level children have their height calculated. If an element has no vertical border or padding, its height is calculated as the distance between the top and bottom border edges of its contained children. Because of this, the top and bottom margins of the contained children appear to protrude from the containing element. However, there is a simple fix. By adding a vertical border or padding, the margins no longer collapse and the height of the element is calculated as the distance between the top and bottom margin edges of its contained children instead.

To get the preceding example looking like Figure 4-27, you simply need to add padding or a border around the div:

#box {

margin: 10px;

padding: 1px;

background-color:#d5d5d5;

}

p{

margin: 20px; background-color:#6699FF;

}

Most problems with margin collapsing can be fixed by adding a small amount of padding or a thin border with the same color as the background of the element in question. A great tool for visualizing how elements interact with each other is the topographic view in the Web Developer Toolbar. Enabling this option gives each element a colored background based on its position in the document. This makes it easy to see how elements are positioned relative to each other in the document (see Figure 4-29).

Figure 4-29. A topographic view of the Mozilla Add-ons site

Another useful tool is the layout view in Firebug (see Figure 4-30), which shows you the various dimensions of the element being inspected.

Figure 4-30. The layout view of the header from the Mozilla Add-ons site

Bug hunting basics

The first step in tracking down a bug is to validate your HTML and CSS to check for typographical or syntactic errors. Some display errors are caused by browsers rendering pages in quirks mode. As such, it is a good idea to check that you are using the correct DOCTYPE for your markup language in order for your pages to render in standards mode . You can tell the mode your page is rendering in by checking it in the Firefox developer’s toolbar. If your page is rendering in quirks mode, the checkmark at the top right of the toolbar will be gray. If your page is rendering in standards mode, the checkmark will turn green. Clicking this checkmark will provide more information about the page, as well as explicitly define the rendering mode (see Figure 4-31).

Figure 4-31. The Firefox web developer’s toolbar shows if your page is displaying in standards or quirks mode

Many Windows developers used to develop their pages primarily using Internet Explorer, so each time they made a change, they previewed the page in IE to see if it was working correctly. Once the pages were almost ready, they would test in a variety of browsers and try to fix any inconsistencies that appeared. However, this is a very dangerous approach that can cause many long-term problems.IE 6 is a notoriously buggy browser with several important CSS flaws. By using IE as their primary development browser, some developers mistakenly interpret IE’s behavior as the correct behavior and wonder why more modern browsers “break” their carefully crafted CSS layouts. In reality, the pages are actually “broken” in IE and are displaying as written in the more standards-compliant browsers.

A much safer approach is to use a more standards-compliant browser, such as Firefox or Safari, as your primary development browser. If your layout works in one of these browsers, it will most likely work correctly in all standards-compliant browsers and is a sign that you’re doing things correctly. You can then test your pages on less-capable browsers and devise workarounds for any display problems you find. Just remember not to leave browser testing until the end of the project. Instead, you should adopt a continual testing methodology, checking your pages in all the major browsers as you go along. That way, you won’t get any nasty surprises at the end of the project when you thought you were almost finished.

Try to avoid bugs in the first place

This advice may sound obvious, but one of the best ways of becoming bug free is to actually avoid problems in the first place. A lot of rendering bugs are caused by overly complicated HTML or CSS. As such, it makes sense to use the simplest code possible to achieve the desired outcome. So avoid overly clever techniques in favor of tried and tested methods, and keep the number of hacks you use to an absolute minimum. Because there are so many different ways of achieving the same effect, consider using a different method before spending hours debugging or hacking a particular technique. Only when you’re sure there’s not a simple way to route around the problem should you try tackling it head on.

Isolate the problem

Once you’re sure you have a bug, you need to try to isolate the problem. By isolating the problem and identifying the symptoms, you can hopefully figure out what is causing the problem and fix it. One way to do this is by applying borders or outlines to the relevant elements to see how they interact:

.promo1 {

float: left;

margin-lrft: 5px;

border: 1px solid red;

}

.promo2 {

float: left;

border: 1px solid green;

}

Borders can be directly added to code, although you could use the outline option in the web developer’s toolbar, or one of many bookmarklets for outlining different elements. Sometimes just the act of adding borders will fix the problem, usually indicating a margin collapsing issue. Try changing a few properties to see if they affect the bug, and if so, in what way. It may be useful to attempt to exaggerate a bug. For instance, if the gap between these two boxes is bigger than you expected in IE, try upping the margin to see what happens. If the space between the boxes in IE has doubled, you have probably fallen foul of IE’s double-margin float bug.

.promo1 {

float: left;

margin-left: 40px;

border: 1px solid red;

}

.promo2 {

float: left;

border: 1px solid green;

}

Try some common fixes. For instance, many IE bugs are fixed by setting the position property to relative, by setting the display property to inline (on floated elements), or by setting a dimension such as width. You will learn more about these common fixes and why they work later in this chapter. Many CSS problems can be found and fixed quickly, with a minimum of effort. If the problem starts to drag on, you should consider creating a minimal test case.

Creating minimal test cases

A minimal test case is simply the smallest amount of HTML and CSS required to replicate the bug. By creating a minimal test case, you help cut out some of the variables and make the problem as simple as possible. To create a minimal test case, you should first duplicate the problem files. Start by removing extraneous HTML until you are left with just the basics. Then start commenting out style sheets to work out which style sheets are causing the problem. Go into those style sheets and start deleting or commenting out blocks of code. If the bug suddenly stops, you know that the last block of code you commented out is contributing to the problem. Keep going until you are left only with the code that is causing the problems.

From here, you can start investigating the bug in more detail. Delete or comment out declarations and see what happens. How does that change the bug? Change property values and see if the problem goes away. Add common fixes to see if they have any effect. Edit the HTML to see if that has any effect. Use different combinations of HTML elements. Some browsers have strange whitespace bugs, so try removing whitespace from your HTML. The list of potential areas for exploration are almost endless.

Fixing the problem, not the symptoms

Once you know the root of the problem, you are in a much better position to implement the correct solution. Because there are many ways to skin a CSS site, the easiest solution is simply to avoid the problem in the first place. If margins are causing you problems, think about using padding instead. If one combination of HTML elements is causing problems, try changing the combination.

Many CSS bugs have very descriptive names. This makes searching for answers on the Web fairly easy. So if you have noticed that IE is doubling the margins on all floated elements, search for “Internet Explorer Double Margin Float Bug” and you are bound to find a solution. If you find that you cannot avoid the bug, you may have to simply treat the symptoms. This usually involves filtering the rule off into a separate style sheet and applying a fix just for that browser.

Asking for help

If you have created a minimal test case, tried common solutions, searched for possible fixes, and still cannot find a solution, ask for help. You’ll find lots of active CSS communities out there, such as CSS-Discuss (www.css-discuss.org/), the Web Standards Group (http://webstandardsgroup.org/), and Stackoverflow (http://stackoverflow.com). These communities are full of people who have been developing CSS sites for many years, so there is a good chance somebody will have experienced your bug before and know how to fix it. If you have a new or particularly intriguing bug, people may be willing to pitch in with suggestions and even help you work out a fix. The thing to remember when asking for help is that most web developers are extremely busy people. If you haven’t validated your code or have simply posted a link to your full site expecting them to trawl through hundreds of lines of HTML/CSS, don’t expect a flood of help. The best way to ask for help on a mailing list or forum is to use a title that accurately describes the problem, write a succinct summary of the problem, and then either paste in your minimal test case or, if it is more than a few lines of code, link to the test case on your site. Annotated screenshots are also useful, as it’s not always obvious from a written description what the problem is, especially if it only affects specific browser versions.

Having layout

We all know that browsers can be buggy, and Internet Explorer 6 seems buggier than most. One of the reasons IE behaves differently from other browsers is because the rendering engine uses an internal concept called layout. Because layout is a concept particular to the internal working of the rendering engine, it is not something you would normally need to know about. However, layout problems are the root of many IE rendering bugs, so it is useful to understand the concept and how it affects your CSS.

What is layout?

Internet Explorer on Windows uses the layout concept to control the size and positioning of elements. Elements that are said to “have layout” are responsible for sizing and positioning themselves and their children. If an element “does not have layout,” its size and position are controlled by the nearest ancestor with layout.The layout concept is a hack used by Internet Explorer’s rendering engine to reduce its processing overhead. Ideally, all elements would be in control of their own size and positioning. However, this causes huge performance problems in IE. As such, the Internet Explorer team decided that by applying layout only to those elements that actually needed it, they could reduce the performance overhead substantially.

Elements that have layout by default include

  • body
  • html (in standards mode)
  • table
  • tr and td
  • img
  • hr
  • input, select, textarea, and button
  • iframe, embed, object, and applet
  • marquee

The concept of layout is specific to Internet Explorer on Windows, and is not a CSS property. Layout cannot be explicitly set in the CSS, although setting certain CSS properties will give an element layout. It is possible to see if an element has layout by using the JavaScript function, hasLayout. This will return true if the element has layout and false if it doesn’t. hasLayout is a read-only property and so cannot be set using JavaScript. Setting the following CSS properties will automatically give that element layout:

  • float: left or right
  • display: inline-block
  • width: any value
  • height: any value
  • zoom: any value (Microsoft property—doesn’t validate)
  • writing-mode: tb-rl (Microsoft property—doesn’t validate)

As of IE 7, the following properties also became layout triggers:

  • overflow: hidden, scroll, or auto
  • min-width: any value
  • max-width: any value except none

What effect does layout have?

Layout is the cause of many Internet Explorer rendering bugs. For instance, if you have a paragraph of text next to a floated element, the text is supposed to flow around the element. However, in IE 6 and below, if the paragraph has layout—because you’ve set the height, for example—it is constrained to a rectangular shape, stopping the text from flowing around the float (see Figure 4-32).

Figure 4-32. Text is supposed to flow around adjacent floated elements. However, in IE on Windows, if the text element has layout, this doesn’t happen

The difference in rendering between browsers can cause all kinds of problems with floated layouts. Worse still, many people who use IE as their main browser mistakenly assume this is the correct behavior and get confused when other browsers treat floats differently. Furthermore, giving something layout appears to clear any floats contained therein, much like setting overflow:hiddenAnother problem revolves around how elements with layout size themselves. If the content of an element becomes larger than the element itself, the content is supposed to flow out of the element. However, in IE 6 and below, elements with layout incorrectly grow to fit the size of their contents (see Figure 4-33).

Figure 4-33. Elements with layout incorrectly grow to fit their contents

This rendering error means that width in IE on Windows actually acts more like min-width. This behavior is also the cause of many broken floated layouts in IE. When the content of a floated box incorrectly forces the width of the box to grow, the box becomes too big for the available space and drops below the other floated elements.

Other problems related to layout include

  • Elements with layout not shrinking to fit
  • Floats being auto-cleared by layout elements
  • Relatively positioned elements not gaining layout
  • Margins not collapsing between elements with layout
  • The hit area of block-level links without layout only covering the text
  • Background images on list items intermittently appearing and disappearing on scroll

You will notice that many of the IE fixes covered later in this chapter involve setting properties that force the element to have layout. In fact, if you come across an IE bug, one of the first things you can do is try applying rules that force layout to see if that fixes the problem. If you would like to learn more about IE’s internal hasLayout property, we recommend reading “On Having Layout” at http://www.satzansatz.de/cssd/onhavinglayout.html.

Thankfully, the IE team fixed most of the layout related problems in IE 7. However, the team did this by spotting common rendering bugs and creating exceptions in the code to handle them, rather than fixing the underlying causes. As such, there may still be a few obscure layout bugs kicking around that have not yet been discovered. IE 8 uses a completely new rendering engine that purportedly ditches the use of the hasLayout property and therefore fixes the cause of these problems.

Workarounds

In an ideal world, properly coded CSS would work in every browser with CSS support. Unfortunately, like all complicated pieces of software, browsers come with their own set of bugs and inconsistencies. In the early days, support for CSS was pretty poor, so developers had to get creative. By using parsing bugs and unimplemented CSS, developers were able to work their way around problems by selectively applying different rules to different browsers. As such, hacks and filters became a powerful weapon in a CSS developer’s arsenal. Thankfully, modern browsers have much better support than their predecessors, so we don’t need to worry about hacks any more. However until older browsers disappear for good, you may find yourself maintaining legacy code. Therefore, it’s a good idea to familiarize yourself with some of the more popular hacks and filters, if only so you can banish them from your code. Before we do this though, let’s take a quick look at conditional comments.

Internet Explorer conditional comments

Conditional comments are a proprietary, and thus nonstandard, Microsoft extension of regular HTML comments. As the name suggests, conditional comments allow you to show blocks of code depending on a condition, such as a browser version. Despite being nonstandard, conditional comments appear to all other browsers as regular comments, so they are essentially harmless. Because of this, conditional comments are generally regarded as the best way to deal with IE-specific bugs. Conditional comments first appeared in IE 5 on Windows and are supported by all subsequent versions of the Windows browser. To deliver a specific style sheet to all versions of IE 5 and above, you could place the following code in the head of your HTML document:

<!– [if IE]

<link rel=”stylesheet” type=”text/css” href=”/css/ie.css” />

–>

Versions of IE 5 and above on Windows would receive the stylesheet ie.css, while all other browsers would simply see some commented-out text. This is interesting but not particularly useful, as it’s rare to find a bug that all versions of Internet Explorer exhibit. Instead, you will probably want to target a specific version or range of versions.

With conditional comments you could target a particular browser such as IE 6.0 using the following code:

<!– [if IE 6]

<link rel=”stylesheet” type=”text/css” href=”/css/ie6.css” />

–>

You could also target sets of browsers such as IE 5 and IE 5.5:

<!– [if lt IE 6]

<link rel=”stylesheet” type=”text/css” href=”/css/ie5x.css” />

–>

As well as using conditional comments to present style sheets to Internet Explorer, you can also use them to hide specific style sheets. Called downlevel-revealed conditional comments, the following syntax will hide more advanced styles from all versions of IE:

<!–[if !IE]>–>

<link rel=”stylesheet” type=”text/css” href=”/css/advanced.css” />

<!–<![endif]–>

And this code effectively hides your styles from Internet Explorer 5.x:

<!–[if gte IE 6]><!–>

<link rel=”stylesheet” type=”text/css” href=”/css/modern.css” />

<!–<![endif]–>

Conditional comments work extremely well and are relatively simple to remember. The main downside is that these comments need to live in your HTML, not your CSS. If a new version of Internet Explorer comes out you may be forced to update the conditional comments on each page of your site. However as long as you remember to do this, you should be fairly safe.

A warning about hacks and filters

As a language, CSS was designed to be very forward compatible. If a browser doesn’t understand a particular selector, it will ignore the whole rule. Likewise, if it doesn’t understand a particular property or value, it will ignore the whole declaration. This feature means that the addition of new selectors, properties, and values should have no adverse effect on older browsers.

You can use this feature to supply rules and declarations to more advanced browsers, safe in the knowledge that older browsers will degrade gracefully. When a new version of the browser is launched, if it now supports the CSS you were using as a filter, it should work as expected. If you are using the more-advanced CSS to circumvent a problem in the older browsers, hopefully this problem will have been solved in the newer version. Because of this behavior, the use of unsupported CSS as a filtering mechanism is a relatively safe option. We say relatively because there is always a chance that the browser will support your new CSS but still exhibit the bug you were trying to fix.

Using filters that rely on parsing bugs is a slightly more dangerous route, because you are relying on a bug, not a feature. Similar to the previous method, if the parsing bug gets fixed but the bug you are trying to fix hasn’t been addressed, you could end up with problems. However, more of a concern is that parsing bugs could find their way into newer versions of browsers. Say, for instance, a new version of Firefox has a particular parsing bug. If that bug is being used as a filter to supply IE with different width values to account for its proprietary box model, all of a sudden Firefox would inherit that width, potentially breaking a lot of sites. It is also worth bearing in mind that these kinds of hacks and filters will often invalidate your code. So as a general rule, it is probably safer to use filters that rely on unsupported CSS, rather than ones that use some kind of browser bug. Or better yet, avoid them all together.

Using hacks and filters sensibly

There is a rather unfortunate overreliance on hacks and filters, especially among those new to CSS. When something does not work in a particular browser, some CSS developers will immediately employ a hack, seeing it as some kind of magic bullet. In fact, a few developers seem to measure their expertise by the number of obscure hacks and filters they know.

If you have done your homework and realize that the only option is to employ some form of hack or filter, you need to do so in a sensible and controlled manner. If your CSS files are small and simple, and you need to employ only a couple of hacks, it is probably safe to place these hacks in your main CSS files with comments indicating that is the case. However, hacks are usually fairly complicated and can make your code more difficult to read. If your CSS files are long and complicated, or you need to use more than a couple of hacks, you may be best separating them into their own style sheets. As well as making your code easier to read, separating out hacks means that if a hack starts causing problems in a future browser, you will know exactly where it is. Similarly, if you decide to drop support for a particular browser, removing the associated hacks is as simple as removing the CSS file.

Applying the IE for Mac band pass filter

Tantek Çelik created a series of filters (http://tantek.com/CSS/Examples/) based on browser parsing errors that allow you to supply stylesheets to selected browsers using the @import rule The filters used to be the recommended way of filtering out various versions of Internet Explorer until conditional comments became commonplace. However, you may still find these filters handy if, for instance, you need to explicitly target is IE 5.2 on the Mac. You can do this using Tantek’s IE 5 for Mac band pass filter, which exploits an escaping bug within CSS comments:

/*\*//*/

@import “ie5mac.css”;

/**/

IE 5 for Mac incorrectly escapes the second asterisk, causing the @import rule to be applied. As such, IE 5 for Mac sees something like this:

/* blah */

@import “ie5mac.css”;

/**/

All other browsers correctly ignore the escaping element, as it is enclosed within a comment, and the @import rule is commented out. Essentially, all other browsers see a rule that looks like this:

/* blah *//*

blah

*/

As with the other band pass filters, it is not necessary to understand how this filter works in order to use it. The beauty of these filters is they specifically target bugs in older, out-of-date browsers. Therefore, you should be able to use these filters safe in the knowledge that they shouldn’t cause problems in newer browsers.

Applying the star HTML hack

One of the best-known and possibly most useful inline CSS filters is known as the star HTML hack. This filter is incredibly easy to remember and targets IE 6 and below. As you are aware, the HTML element is supposed to be the first, or root, element on a web page. However older versions of IE have an anonymous root element wrapping around the HTML element. By using the universal selector, you can target an HTML element enclosed inside another element. Because this only happens in IE 6 and below, you can apply specific rules to these browsers:

* html { width: 1px;

}

As this bug was fixed in IE 7, it is a relatively safe way of targeting older versions of IE. This hack forms part of the modified simplified box model hack (MSBMH), which used to be a popular way of managing Internet Explorer’s propriety box model in older browsers.

#content {

width: 80px;

padding: 10px;

}

* html #content {

width: 100px;

w\idth: 80px;

}

While we wouldn’t recommend using this technique now, it is useful to know what it looks like as you may come across it in legacy code.

Applying the child selector hack

Instead of explicitly targeting older versions of Internet Explorer, say that you wanted to create a rule that these browsers will ignore. You can do this by using the child selector hack, though this technique isn’t really a hack, as it simply uses a selector that older versions of IE don’t understand but more modern browsers do. In this example, the child selector hack is being used to hide a transparent background PNG image from IE 5-6 on Windows:

html>body {

background-image: url(bg.png);

}

This rule will be hidden from older versions of Internet Explorer. However, IE 7 supports both the child selector and native PNG transparency, so it will interpret the code correctly.

Common bugs and their fixes

One of the greatest skills any CSS developer can have is the ability to spot common browsers bugs. By knowing the various elements that conspire to cause these bugs, you can spot and fix them before they ever become a problem.

Double-margin float bug

One of the most common and easy-to-spot bugs is the double-margin float bug in IE 6 and below. As the name suggests, this Windows bug doubles the margins on any floated elements (see Figure 4-34).

Figure 4-34. Demonstration of IE on Windows’s double-margin float bug

This bug is easily fixed by setting the display property of the element to inline. As the element is floated, setting the display property to inline won’t actually affect the display characteristics. However, it does seem to stop IE 6 and below on Windows from doubling all of the margins. This is such a simple bug to spot and fix: every time you float an element with horizontal margins, you should automatically set the display property to inline, just in case margin gets added in the future.

Three-pixel text jog bug

Another bug very common in IE 5 and 6 on Windows is the three-pixel text jog bug. This bug manifests itself when you have text adjacent to a floated element. For instance, say you had an element floated left, and you don’t want the text in the adjacent paragraph to wrap around the float. You would do this by applying a left margin to the paragraph, the same width as the image:

.myFloat {

float: left;

width: 200px;

}

p {

margin-left: 200px;

}

When you do this, a mysterious 3-pixel gap appears between the text and the floated element. As soon as the floated element stops, the 3-pixel gap disappears (see Figure 4-35).

Figure 4-35. Demonstration of the IE 5 and 6 three-pixel text jog bug

Fixing this bug requires a two-pronged attack. First, the element containing the text is given an arbitrary height. This forces the element to have layout, which seemingly removes the text jog. Because IE 6 and below on Windows treat height like min-height, setting a tiny height has no effect on the actual dimensions of the element in that browser. However, it will affect other browsers, so you need to hide this rule from everything other than IE 6 and below on Windows. The best way to do this is to move these styles into a separate CSS file using conditional comments.

p {

height: 1%;

}

Unfortunately, this technique causes another problem. As you learned earlier, elements with layout are constrained to a rectangular shape and appear next to floated elements rather than underneath them. The addition of 200 pixels of padding actually creates a 200-pixel gap between the floated element and the paragraph in IE 5 and 6 on Windows. To avoid this gap, you need to reset the margin on IE 5-6/Win back to zero:

p{

height: 1%;

margin-left: 0;

}

The text jog is fixed, but another 3-pixel gap has now appeared, this time on the floated image. To remove this gap, you need to set a negative 3-pixel right margin on the float:

p{

height: 1%;

margin-left: 0;

}

.myFloat {

margin-right: -3px;

}

This will fix the problem if the floated element is anything other than an image. However, if the floated element is an image, there is one last problem to solve. IE 5.x on Windows adds a 3-pixel gap to both the left and the right of the image, whereas IE 6 leaves the image’s margins untouched. As such, if you need to support IE 5.x, you will want to have one style sheet for those browsers:

p{

height: 1%;

margin-left: 0;

}

img.myFloat {

margin: 0 -3px;

}

and another for IE 6:

  1. {

height: 1%;

margin-left: 0;

}

img.myFloat {

margin: 0;

}

IE 6 duplicate character bug

Another curious bug involving floats is IE 6’s duplicate character bug. Under certain conditions, the last few characters in the last of a series of floats will be duplicated beneath the float, as shown in Figure 4-36.

Figure 4-36. Demonstration of IE 6’s duplicate character bug

This bug manifests itself when you have multiple comments in between the first and last of a series of floated elements. The first two comments have no effect, but each subsequent comment causes two characters to be duplicated. So three comments would result in two duplicate characters; four comments would result in four duplicate characters; and five comments would result in six duplicate characters.

<div id=”content”>

<!– mainContent –>

<div id=”mainContent”>

</div><!– end mainContent –>

<!– secondaryContent –>

<div id=”secondaryContent”>

</div>

Strangely, this bug seems related to the three-pixel text jog bug you saw previously. To fix the bug, you can remove 3 pixels from the final float by setting a negative right margin or make the container 3 pixels wider. However, both these methods are likely to cause problems in IE 7, which isn’t expected to exhibit this bug. Because of this, the easiest and safest way to avoid this bug is to remove the comments from your HTML code.

IE 6 peek-a-boo bug

Another strange and infuriating bug is IE 6’s peek-a-boo bug, so called because under certain conditions text will seem to disappear, only to reappear when the page is reloaded. This happens when there is a floated element followed by some nonfloated elements and then a clearing element, all contained within a parent element that has a background color or image set. If the clearing element touches the floated element, the nonfloated elements in between seem to disappear behind the parent element’s background color or image, only to reappear when the page is refreshed (see Figure 4-37).

Figure 4-37. Demonstration of IE 6’s peek-a-boo bug

Luckily, there are a number of ways you can combat this bug. The easiest way is probably to remove the background color or image on the parent element. However, this is often not practical. Another way is to stop the clearing element from touching the floated element. The bug doesn’t seem to manifest itself if the container element has specific dimensions applied. The bug also doesn’t manifest itself if the container is given a line height. Last, setting the position property of the float and the container to relative also seems to alleviate the problem.

Absolute positioning in a relative container

The last major browser bug we going to cover involves absolutely positioned elements within a relatively positioned container. You learned in earlier chapters how useful nesting an absolutely positioned element in a relative container can be. However, IE 6 and below have a number of bugs when you use this technique. These bugs arise from the fact that relatively positioned elements don’t gain IE on Windows’s internal hasLayout property. As such, they don’t create a new positioning context, and all of the positioned elements get positioned relative to the viewport instead (see Figure 4-38).

Figure 4-38. Demonstration showing how IE 5.x incorrectly positions absolutely positioned elements within a relative container

To get IE 6 and below on Windows to behave correctly, you need to force the relatively positioned container to have layout. One way to do this is to explicitly set a width and height on the container. However, you will often want to use this technique when you don’t know the width and height of the container, or when you want one or both of these properties to be flexible. Instead, you can use conditional comments to filter out IE 5 and 6 and then give the container layout by applying an arbitrary dimension. Because elements in IE 6 and below incorrectly expand to fit their contents, the actual height won’t be affected.

.container {

height: 1%;

}

Stop picking on Internet Explorer

Internet Explorer isn’t the only buggy browser around, so you may wonder why we have been focusing  attentions on IE bugs. Don’t worry; it’s not another case of Microsoft bashing; there are good reasons for this focus. First, IE still has a significant market share so bugs tend to get found and documented pretty quickly. However, the pace of development is much slower in IE than other browsers. So, while Firefox and Safari are releasing new builds every few months, it can take years to see a new version of IE. As such, IE bugs tend to stick around longer.

The speed at which bugs are found and fixed in Firefox and Safari is excellent, but it does have its own problems. Rather than having two or three versions of a browser to deal with, you may have 10 or 20. You can never be sure if your users have the latest version, and this makes testing extremely difficult. IE, on the other hand, didn’t see a major revision for about five years. As such, there has been much more time for bugs to surface and much more impetus to find a fix.

Luckily, IE 8 is a much more standards-compliant browser than previous versions. Many of the better-known IE bugs have been addressed, along with increased support for advanced CSS 2.1. As with all browsers, new bugs will surface, and IE 8 is far from perfect. However, the faster people can be convinced to upgrade to modern browsers such as IE 8 and Firefox, the quicker older browsers such as IE 6 can be retired.

Graded browser support

No discussion about bugs would be complete without mentioning browser support. Each time a new version of Internet Explorer comes out, the release sparks a big discussion about when it is going to be safe to stop supporting the previous versions. After all, if Microsoft no longer officially supports IE6, why should we bother? Unfortunately, there is no clear solution to the problem of browser support, and the honest answer is that it depends on the individual site.

If you are hosting a site for web developers, you probably have a large Firefox and Mac user-base, in which case IE 6 usage may be so low as to deem it not worth worrying about. However, even a couple of percent on a site that receives a million visitors a month could equate to tens of thousands of unhappy customers. For business or consumer sites, the number of IE 6 users is likely to be much higher. You may even find that on specific sites IE 6 usage outstrips that of IE 7. This is because many corporate IT departments lock their users into specific browser versions, while many home users only update their browsers when they get a new machine. So instead of talking about dropping support for a certain browser, we need to grade on the curve and decide what support actually means on a site-by-site basis. This is where the idea of graded browser support comes in.

Large organizations like Yahoo and the BBC realize that not all browsers are created equal and that ensuring your site looks and behaves exactly the same in all browsers will increase maintenance costs while hampering innovation. In order to avoid having to design for the lowest common denominator in browser terms, these companies have started to adopt graded support charts (see Figures 4-39 and 4-40). Rather than seeing browser support as a binary supported/unsupported option, these charts offer a variety of different support levels, from rendering the full design for modern browsers, down to just the content for older versions. While each organization frames the problem differently, the steps are pretty much the same.

First, you need to identify the browsers for which you want to ensure render consistently across your site and then test on all of these browsers. This group will usually contain the latest and most popular browsers used by your audience. So the latest versions of Firefox, Safari, and Opera, as well as IE 7 and 8 will probably fall into this category. With these browsers, you want the sites to look largely the same, although for practical reasons a couple of pixels here or there won’t make much difference.

Figure 4-39. Yahoo’s graded browser support chart for A-grade browsers

Figure 4-40. Graded browser support table at the BBC

Next, you identify a set of aging but still important browsers. This could include older versions of Firefox and Safari along with IE 6. You’ll test on a random sampling of these browsers and attempt to fix any problems you find. However, you’ll accept that rendering may not be perfect and may differ from browser to browser, just as long as the content is accessible.

Last, you’ll identify a set of obscure or out-of-date browsers that you don’t officially support. This would be browsers like IE 4, Netscape Navigator 4, or Opera 7. With these browsers, you still want to make the content and functionality available, but you’re not worried about the presentation. As such, you are happy to accept fairly major design variations. Even better would be to remove the styling from these browsers altogether.

A graded support philosophy gives you a much more flexible way of dealing with the volume of browsers and other user agents out there. The charts from the BBC are a good starting point, but as every site is unique, we strongly recommend that you create your own on a project-by-project basis.

Summary

In this chapter, you learned how to create simple two- and three-column fixed-width layouts using floats. You then learned how these layouts could be converted into liquid and elastic layouts with relative ease, as well as exploring some of the problems associated with these layouts and how setting maximum widths in ems or pixels can offer solutions. You also saw how to create full height column effects on both fixed-width and flexible layouts, using vertically repeating background images. This chapter also touched on some of the techniques used to create CSS-based layouts. However, there are a lot of techniques out there, enough to fill a whole book of their own. Last, you learned some of the dangers inherent in CSS frameworks and the importance of developing your own CSS system instead.

In this chapter, you have learned some important techniques for tracking down and squashing CSS bugs. You have learned about IE on Windows internal hasLayout property and how this is the root of many IE on Windows browser bugs. You also learned about some of the most common browser bugs and how to fix them. Finally, you’ve learnt how to deal with a plethora of different browsers through the use of graded support charts.

This Is A Custom Widget

This Sliding Bar can be switched on or off in theme options, and can take any widget you throw at it or even fill it with your custom HTML Code. Its perfect for grabbing the attention of your viewers. Choose between 1, 2, 3 or 4 columns, set the background color, widget divider color, activate transparency, a top border or fully disable it on desktop and mobile.

This Is A Custom Widget

This Sliding Bar can be switched on or off in theme options, and can take any widget you throw at it or even fill it with your custom HTML Code. Its perfect for grabbing the attention of your viewers. Choose between 1, 2, 3 or 4 columns, set the background color, widget divider color, activate transparency, a top border or fully disable it on desktop and mobile.