Having “layout”
We all know that browsers can be buggy, and IE on Windows seems buggier than most. One of the reasons IE/Win 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/Win 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 IE’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 IE/Win development 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, td
- img
- hr
- input, select, textarea, button
- iframe, embed, object, applet
- marquee
The concept of layout is specific to IE 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:
- position: absolute
- 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)
What effect does layout have?
Layout is the cause of many IE/Win 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 on Windows, if the paragraph has layout—by setting the height, for example—it is constrained to a rectangular shape, stopping the text from flowing around the float (see Figure below).
Figure Above: Text is supposed to flow around adjacent floated elements. However, on IE/Win, if the text element has layout, this doesn’t happen.
Another 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 on Windows, elements with layout incorrectly grow to fit the size of their contents (see Figure below).
Figure Above: Elements with layout incorrectly grow to fit their contents.
This means that width in IE/Win actually acts more like a min-width. This behavior is also the cause of many broken floated layouts in IE/Win. 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 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
In the next section, we are going to cover some of the most common browser bugs, and you will notice that many of the fixes for IE on Windows involve setting properties that force the element to have layout. In fact, if you come across an IE/Win 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, I recommend reading “On Having Layout” at http://tinyurl.com/acg78.
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 below).
Figure Above: Demonstration of IE/Win’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.
Three-pixel text jog bug
Another very common IE 5-6/Win bug is the 3-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 Below).
Figure Above: Demonstration of the IE 5-6/Win’s 3-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 treats 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 the Holly hack is used to hide this rule from everything other than IE 6 and below on Windows:
/* Hide from IE5-Mac. Only IE-Win sees this. */
* html p { height: 1%; }
/* End hide from IE5/Mac */
Unfotunately, doing this 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-6/Win. To avoid this gap, you need to reset the margin on IE 5-6/Win back to zero:
/* Hide from IE5-Mac. Only IE-Win sees this. */
* html p { height: 1%; margin-left: 0; }
/* End hide from IE5/Mac */
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:
/* Hide from IE5-Mac. Only IE-Win sees this. */
* html p { height: 1%; margin-left: 0; }
* html .myFloat { margin-right: -3px; }
/* End hide from IE5/Mac */
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/Win 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, another hack is required to remove the 3-pixel gap from IE 5.x/Win only:
/* Hide from IE5-Mac. Only IE-Win sees this. */
* html p { height: 1%; margin-left: 0; }
* html img.myFloat { margin: 0 -3px; margin: 0; }
/* End hide from IE5/Mac */
This solves the problem, but in a really nasty and complicated way. As such, if possible you would be better off splitting these rules up into separate, browser-specific stylesheets. If you did this, you could have one stylesheet for IE 5.x on Windows:
p { height: 1%; margin-left: 0; }
img.myFloat { margin: 0 -3px; }
And another for IE 6:
p { height: 1%; margin-left: 0; }
img.myFloat { margin: 0; }
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 Below).
Figure Above: 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. Lastly, 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 I am 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 has a number of bugs when you use this technique.
These bugs arise from the fact that relatively positioned elements don’t gain IE/Win’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 Below).
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 the Holly hack to supply an arbitrary height to the container. This will give the container layout, but because elements in IE 6 and below incorrectly expand to fit their contents, the actual height won’t be affected.
/* Hides from IE-Mac */ * html .container { height: 1%; } /* End hide from IE-Mac */
Stop picking on Internet Explorer
Internet Explorer isn’t the only buggy browser around, so you may wonder why I have been focusing my attentions on IE bugs. Don’t worry, it’s not another case of Microsoft bashing; there are good reasons for this focus.
First, IE has by far the biggest browser market share. With so many copies in circulation, IE bugs tend to get found and documented pretty quickly. When a major CSS bug gets discovered in IE, scores of developers will be on the case trying to find a fix or a workaround. Because of this popularity, there are more well-documented bugs and fixes for IE than any other browser.
The other major issue is the pace of development. Browsers such as Firefox, Safari, and Opera are constantly being updated, with new builds appearing with remarkable frequency. Almost as soon as a bug is discovered, it is fixed and a new version of the browser released. Because of this, any Firefox or Safari bug I talk about now will probably have been fixed by the next revision.
This pace of development 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 20 or 30. 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 5 years. As such, there has been much more time for bugs to surface and much more impetus to find a fix.
Luckily, IE 7 promises to be a much more compliant browser. Many of the better known IE bugs have been addressed, along with increased support for advanced CSS 2.1 selectors such as the child and attribute selectors. As with all browsers, new bugs will surface, and IE 7 will be far from perfect. However, the faster people can be convinced to upgrade to modern browsers such as IE 7 and Firefox, the quicker older browsers such as IE 5.0 can be retired.
In the interim, it is worth exploring Dean Edwards’ excellent IE 7 patch. This series of JavaScript files aims to bring IE 5-6/Win up to speed with IE 7. This includes improved selector implementation and numerous bug fixes. For more information about this patch, visit http://dean.edwards.name/IE7/.
Summary
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/Win browser bugs. Finally, you have learned about some of the most common browser bugs and how to fix them.
Next you will see how all of this information can be put together, through two stunning case studies created by two of the best CSS designers and developers of our time.