Defeating IE5 CSS bugs with the help of jwz
Today’s CSS case study will be Jamie Zawinski’s LiveJournal. OK, I admit that he’s something of a tempting target after his widely publicised CSS rant last month (which was the main inspiration for this course), but there are a number of sensible reasons his site makes a good case study as well. The theme for today is “bugs in IE5 for Windows”, and jwz’s site offers two classic examples that fit this theme nicely. The first is the fact that the design is centered on the page, and the second is his choice of Verdana, a font which requires some trickery to get working well in IE5. In addition, the design of the entries seems to be a natural fit for a table based layout, so demonstrating how much simpler the code can be in CSS will hopefully turn a few heads.
Here’s the “before” screenshot:

And here’s the original HTML (I’ve added some newlines but other than that it’s as seen on the page):
<table summary="" border="0" cellpadding="2" class="entrybox" width="600"
cellspacing="0">
<tr align="left">
<td align="center" bgcolor="#00CC00">
<table summary="" border="0" cellpadding="5" width="100%" cellspacing="0">
<tr align="left">
<td class="caption">Life isn't fun 24 hours a day, so shopping should be.</td>
<td class="index" align="right">[18 May 2003|<b>04:09pm</b>]</td>
</tr>
<tr align="left">
<td bgcolor="#000000" colspan="2">
<table summary="" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="meta">[</td>
<td class="meta" align="right"><b>music</b></td>
<td class="meta" align="center">|</td>
<td class="meta">Luscious Jackson -- Bam Bam</td>
<td class="meta">]</td>
</tr>
</table><p>
<p><a href="
http://www.nytimes.com/2003/05/18/magazine/18TOKYO.html?8hpib=&pagewanted=all">
The Economy of Cool</a> <p> Katayama has a dozen or so interiors to his credit in
Harajuku-Aoyama, Tokyo's fashion and design district. All within walking distance
of one another, they are boutiques that, in almost every case, aggressively cater
to a youthful clientele for whom shopping is an adored cultural pursuit. ''You're
not just buying the product,'' Katayama says. ''You're also buying the time you
spend.'' [...] <p> Now 36, Masamichi Katayama studied interior design in Osaka,
although he is quick to point out that it was strictly technical training, with
no theoretical or academic courses. ''I learned the philosophy of what I do by
shopping,'' he says. ''I'm a consumer first and foremost. Life isn't fun 24 hours
a day, so shopping should be.'' He lights cigarette after cigarette as he speaks,
taking no more than three drags on each before moving on to the next. [...] <p>
</td>
</tr>
<tr>
<td class="comments" width="100%" align="right" bgcolor="#004400" colspan="2">
<a href="http://www.livejournal.com/~jwz/203141.html"><b>2 comments</b></a>|
<a href="http://www.livejournal.com/~jwz/203141.html?mode=reply">post comment</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
That’s three tables for every entry on the page. If we trim it down to basic structural HTML, we get the following:
<div class="entry">
<p class="date">[18 May 2003|<strong>04:09pm</strong>]</p>
<h2>Life isn't fun 24 hours a day, so shopping should be.</h2>
<p class="music">[<strong>music</strong>|Luscious Jackson -- Bam Bam]
<p><a href="
http://www.nytimes.com/2003/05/18/magazine/18TOKYO.html?8hpib=&pagewanted=all">
The Economy of Cool</a></p>
<p>Katayama has a dozen or so interiors to his credit in Harajuku-Aoyama,
Tokyo's fashion and design district. All within walking distance of one
another, they are boutiques that, in almost every case, aggressively
cater to a youthful clientele for whom shopping is an adored cultural
pursuit. ''You're not just buying the product,'' Katayama says.
''You're also buying the time you spend.'' [...] </p>
<p>Now 36, Masamichi Katayama studied interior design in Osaka, although he is
quick to point out that it was strictly technical training, with no
theoretical or academic courses. ''I learned the philosophy of what I
do by shopping,'' he says. ''I'm a consumer first and foremost. Life
isn't fun 24 hours a day, so shopping should be.'' He lights cigarette
after cigarette as he speaks, taking no more than three drags on each
before moving on to the next. [...] </p>
<p class="comments">
<a href="http://www.livejournal.com/%7Ejwz/203141.html" class="count">2 comments</a>
|<a href="http://www.livejournal.com/%7Ejwz/203141.html?mode=reply">post comment</a>
</p>
</div>
That’s quite a substantial reduction in markup. Here’s what it looks like. The challenge now is to make it look like it does in the picture.
First, let’s set a few basic rules. JWZ’s site has green text on a black background, both of which should be set as rules on the document body (they could be set on individual elements but since they apply to the whole document it’s best to define them higher up):
body {
background-color: #000;
color: #0f0;
}
Note that while the original site uses #000000 and #00FF00 as hexadecimal colour attributes on the body tag, I have used #000 and
#0f0. Since many common colours can be represented using three pairs of hexadecimal digits, CSS allows you to use three instead of six and will “double” each digit in its place. color: #00ff00; would have exactly the same effect.
Setting the font size (IE bug #1)
Now it’s time to tackle our first IE5/Windows specific bug. Verdana is an extremely popular font among web designers, but suffers from the unfortunate problem that it is sinfully ugly when displayed at the browser’s default text size. Knock it down just one size and it becomes a great deal pretty, while remaining completely readable. As a result, if we want to use Verdana we really need to make it smaller.
CSS provides a truly huge range of font sizing options, and each and every one of them carries its own set of flaws and limitations thanks to differences in implementation between the many CSS supporting browsers. A good resource for understanding the scope of this problem is Owen Brigg’s excellent Text Sizing article, which includes 274 screenshots of different font sizing techniques in different environments. To cut a long story short, the only reliable cross browser sizing method is to specify the size of the font in pixels. This comes with one massive drawback: doing so will prevent IE users from resizing the text in their browsers. If you care at all about accessibility you’ll know why this is a bad idea.
No matter which font sizing technique you use, it is widely recognised that the best way of dealing with font sizes is to set a single basic font size on the body and then size other text on the page relative to that initial size using ems (described briefly last tutorial) or percentages. Personally, I like to use a font such as Georgia which looks good at the default browser size setting and avoid the whole issue of setting an initial size, but as we have already discussed if you are using Verdana this is pretty much out of the question. When forced to resize the default font, my favoured method is to use the font-size keywords small and x-small.
This is where the IE5 bug comes in. Most browsers (including IE6 in standards mode, all Gecko engine browsers and Opera 7) display Verdana at the size I prefer if you specify font-size: small. IE5 for Windows on the other hand requires font-size: x-small. Since IE5 still has a relatively large market share, it’s important to get things looking good in that browser, no matter how irritating it’s support of CSS. It’s time to apply a hack...
Hacks are something of a controversial issue within the CSS community. Some people see them as an anathema to everything that CSS is meant to represent, while others (myself included) see them as a slightly unpleasant tool that can help achieve a practical end. Since the focus of this tutorial is on the practical applications of CSS, I’ll leave discussions of the validity of hacks to the css-discuss wiki.
The hack I shall be using here is the famous Box Model Hack by Tantek Celik. Originally devised to get around a serious flaw in IE’s implementation of the box model (to be covered later in the course), the box model hack allows a CSS author to feed one value to IE5 and another to better, more standards compliant browsers. We want to give IE5 x-small and everything else small, and here’s the code we are going to use:
body {
background-color: #000;
color: #0f0;
font-family: verdana, sans-serif;
font-size: x-small;
voice-family: "\"}\"";
voice-family: inherit;
font-size: small;
}
html>body {
font-size: small;
}
Ugly, isn’t it? The way it works is explained elsewhere, but believe it or not the above code will kick IE5 in to line with the rest of the mainstream browsing world. Here’s how it looks. Let’s move on.
Styling the Entry
Now that text sizing is out of the way, we can get on with styling the entry itself. First, let’s look at the div surrounding each entry. Firstly, it needs to be 600 pixels wide to match the width of the table in the original. The original design has a 2 pixel wide line around the edge of the table, and we can replicate this using a CSS border. Borders in CSS can be applied to the top, left, right and/or bottom of an element in any colour, any thickness and a number of different styles: they are a very powerful tool. In this case we just need a 2 pixel wide green border around the whole div. Here’s the CSS:
div.entry {
width: 600px;
border: 2px solid #0c0; /* Applied all the way around the div */
}
The entry title is a critical part of the design. We have used an h2, but we need to style this with a green background and correctly sized black text. Headers always come with a default margin above and below the header, but since we are using the background colour of the element as part of the design we need to eliminate this by specifically setting the margins around the element to 0. We also need some padding to give the text inside the element some space—trial and error leads us to set this at 5 pixels:
h2 {
margin: 0;
padding: 5px;
font-size: 1em;
color: #000;
background-color: #0c0;
}
The date for each entry appears alongside the title, on the right hand side. As we saw last time, this can be achieved with a float. I’ll also set the font size to 0.85em (again found using trial and error) and add some padding to ensure the date appears inline with the heading:
div.entry p.date {
font-size: 0.85em;
float: right;
color: #000;
background-color: #0c0
margin: 0;
padding-top: 5px;
padding-right: 5px;
}
I’ve specified the background-color again because it is good practise to always set a background colour at the same time as you set the colour of an element. This helps ensure you never accidentally end up with unreadable text that is the same colour as its background.
Here’s what our redesign looks like now.
Tidying up the text
There are two glaring problems with what we now have. Firstly, there is no space between the borders and the text. Secondly, the link colours aren’t as they should be. We can lift the link colours straight from the attributefs on the body tag in the original site:
a:link {
color: #00DDFF;
text-decoration: none;
}
a:visited {
color: #FF6633;
}
We are using a:link as the selector rather than just a on its own, because a will match all <a> elements including those that are just being used as a link target. There aren’t any on the page, but it’s a good idea to get in to the practise of using a:link to style links anyway. a:visited applies styles to visited links. The :something syntax is called a pseudo-selector. It’s also worth noting an accessibility point here: it’s generally a very bad idea to set links apart from normal text by colour alone, so text-decoration: none should be discouraged unless some other non-colour based visual indicator is also specified. I’m ignoring that for this example in order to comply with the original design.
Space between the border and the text can be added in a number of ways: as padding within the entry, as a margin on the paragraphs or as padding on the paragraphs. Since we have set a width on the entry it’s a good idea to avoid adding padding to this as this can result in IE5 misbehaving (a box model problem, which could be solved by the box model hack but why hack when you can possibly avoid it?). Instead we will set a margin on the paragraphs:
div.entry p {
margin: 1em 5px;
}
Here we are using another CSS shorthand. Both padding and margin properties can be set with one, two, three or four properties. If only one is provided, it is applied to all four sides. If two are provided (as in this example) the first is applied to top and bottom and the second to left and right. If four are provided, they apply to Top, Right, Bottom, Left respectively (a good mnemonic for this is TRouBLe, which I picked up from Eric Meyer). Behaviour for three properties is defined but it’s quite complicated so I recommend avoiding it entirely. The upshot of all this is that the above rule adds a 1em margin to the top and bottom of each paragraph and 5 pixels to either side. You’d be forgiven for thinking that this means margins would be spaced 2 ems apart, but in fact the margins on elements on top of each other collapse to fill the space of just one. I’ll talk about this more when I cover the box model in detail.
The styles for the comments section at the bottom (complete with dark green background) and the music section at the top of the entry should be pretty self explanatory, so I’ll provide them here without further analysis:
div.entry p.comments {
background-color: #040;
margin: 0;
padding: 5px;
text-align: right;
font-size: 0.85em;
}
p.comments a.count {
font-weight: bold;
}
div.entry p.music {
font-size: 0.85em;
margin-top: 0.5em;
}
Note that both paragraphs have a margin explicitly set—this is important as we need to over-ride the margin set on all paragraphs within div.entry earlier on. This is also related to the reason the full div.entry p.comments selector is used instead of just p.comments—if you want to know the full reason for this, look up the CSS specificity rules which are outside the scope of this article.
Centering the DIV
We’re nearly there! All that remains is to center the div on the page. This is the point where our second IE5/Windows bug rears it’s ugly head...
The standard way of centering a block level element (for example a div or a paragraph) in CSS is to set the left and right margins of the paragraph to “auto”. This can be achieved using the shorthand property explained above: margin: 0 auto;. Were it not for IE5, our troubles would be over. Unfortunately, IE5 fails to recognise this method.
As luck would have it, we can now use another IE5 bug to our advantage. The text-align: center declaration, as you might expect, aligns text in the center of the element. IE5 incorrectly also applies the property to block level elements, which include our troublesome div. So we can set text-align: center on our body element and all is well...?
Not quite. Like most text properties (such as the font-size property we were playing with earlier) text-align is inherited. If we center the text in our body, we end up centering it in all of our other elements as well. Luckily we can use text-align: left on the other elements in our document to prevent this from happening. Combine these three CSS tricks and you get the following method for centering elements in an IE5 friendly way:
body {
...
text-align: center;
}
div.entry {
...
margin: 0 auto;
}
body div, body p, body h2 {
text-align: left;
}
Which brings us to our final result: JWZ’s blog entries in pure CSS. It took quite a bit of work, but I think the results speak for themselves.
What you should have learned
While most designs can be achieved in CSS, some are harder than others. This is not the fault of CSS; it is more a problem with faulty browser implementations of CSS. When people call IE5/Windows the “new Netscape 4”, they are doing so with good reason! However, IE5’s deficiencies are well understood with the CSS community and workarounds exist which, while initially tricky, for the most part work very well. With a bit of insider knowledge the beast can be tamed.
In this tutorial I’ve tried to roll up my sleeves and get stuck in to the dirtier side of CSS development. I’ve demonstrated some hacks, and I’ve shown how there can be more to practical CSS than meets the eye. It may seem like an awful lot of work, but in fact the initial jwz remake took me just over half an hour thanks to my previous experience with IE5 bugs.
For the next installment, I will be stepping back from hacks and unpleasantries and looking at CSS being used in a much simpler light: to visually enhance semantically structured page elements. I also have another case study planned which will make much lighter reading than this one. As always, comments are welcome.
And finally, apologies to jwz for borrowing without asking. I hope I haven’t caused offence.
Argh, Verdana. It has an unusually large aspect ratio compared with most fonts. That is because it is designed for use at small font sizes, and also is the reason why most people think it looks "big" at normal size.
Not everybody has Verdana installed. Some people have configured their systems to display another font instead. There are plenty of reasons why a font other than Verdana would be displayed, even if you specify it in your HTML/CSS.
The result? Unreadably small text. Read more in this thread.
Actually, the only reliable thing that will do is annoy people. Apart from the mentioned IE problems, it doesn't get around the basic fact that I have chosen my font size already - do you really know better than me which font size is most appropriate? Do you really want me to fiddle with my font size every time I go to a different site? Please, just leave it at 100%, or, if you must reduce it a little, 90% of my default.
Jim - 21st May 2003 00:17 - #
Simon Willison - 21st May 2003 00:24 - #
Phillip Pearson - 21st May 2003 00:55 - #
Simon Willison - 21st May 2003 01:01 - #
>>do you really know better than me which font size is most appropriate?
In the vast majority of cases, yes. Most people don't know how to change their default font size. And all the cool people use ctrl++ on Moz anyway, such as when they visit zeldman.com ;-)
(Man, this site is tough to post on. What's wrong with a br tag in xhtml format? How about a nice button to add p tags, Simon?)
stylo~ - 21st May 2003 04:21 - #
The hack not only effects MSIE5.0, but also MSIE6.0 since MSIE6.0 doens't recognize child-selectors. I don't know if that's a problem here.
Anne van Kesteren - 21st May 2003 06:27 - #
About the box model hack: vastly superior I think is to put all your IE-only css code within IE conditional comments (style tags within conditional comments) just below your css file. With dynamic sites you just include a file callled ie_css_hacks.cfm or whatever. Much neater, easier to delete later, and your css file is left alone. You can also easily target each IE version within the comments, whereas, with a css hack, you never know what other emerging browser might get caught (safari, etc.)
stylo~ - 21st May 2003 07:21 - #
Oops I said something wrong. I thought u did some like this:
p{font-size:x-small;}body > p{font-size:small;}I use the hack above myself sometimes. If I use him I set MSIE6.0 to quirck-mode setting a xml-declaration. I also like stylo~'s method. But I think this methode is nicer.
Anne van Kesteren - 21st May 2003 07:44 - #
You might also like to discuss in your tutorials why is it normally preferable to use SGML 'comment delimiters' for surrounding embedded style rule blocks, which may appear within an HTML source document, for example:
<style type="text/css"> <!-- I am Stylesheet Character Data. --> </style>
If we were being purest and thinking along the lines of XML and XHTML then you could consider CDATA sections commenting, for example:
... <![CDATA[ I am Character Data. ]]> ...
They are both minor details but they are worth mentioning, just for completeness and old browser compatibility issues, etc.
Robert Wellock - 21st May 2003 13:05 - #
BODYto a percentage and use ems for other sizes) to be easier and a lot more sensible.kirkaracha - 21st May 2003 18:39 - #
In the field of education, there are many different learning styles -- visual, aural, kinesthetic -- and not everyone learns the same way. Then there are people who have neither the time nor the inclination to learn. While I appreciate and admire your efforts to educate, why not just cut out the foreplay and give the code?
As I've stated publicly, I'd like a "Open Source Universal Stylesheet" for different designs -- similar to what the Noodle Incident attempted. There are many more people who would be grateful to you to get code than there are who would be grateful for another CSS tutorial. After all, there's a bazillion CSS books and tutorials out there, but nobody is "Giving the Code."
Kind regards,
Vincent Flanders - 21st May 2003 19:34 - #
Joe Grossberg - 21st May 2003 21:14 - #
Vincent - thanks for the feedback. I understand your point about code being more directly valuable than lengthy explanations, but there are plenty of sites out there doing that already. I think the reason people have trouble with CSS is the weird edge cases - things like the IE5 bugs I've described in this article. You can't learn them from looking at code because often they're quite subtle, so the approach I'm taking is to explain them in as much detail as possible so people can understand what causes them and exactly how the workarounds are constructed.
I make the code for the examples I'm providing available on a separate page partly so people can see it working for themselves and partly so anyone who just wants the code can grab it without having to read through the lengthy analysis. Thinking about it, I should probably link to the final result from the top of the article so people who just want the code can grab it and go. I'll make that change when I update the articles later on today.
Simon Willison - 22nd May 2003 00:04 - #
ryan gantz - 22nd May 2003 02:11 - #
body * { text-align: left; }BTW: What's up with blockquotes not being able to contain code? I had to settle for a paragraph. :-(Steven Vasilogianis - 23rd May 2003 08:57 - #
I should probably point out that this is not "my" layout, this is just one of the LiveJournal presets (the one called "Generator", I believe.) All I did was choose the colors.
I certainly would never have chosen that font, or any font, for that matter. In my opinion, web pages should never set fonts or font sizes on their main body text: that should always be left up to the user. If the user likes Verdana or whatever, they would have chosen that in their browser preferences. If my web page sets a font, then at best it will be inoffensive, and most of the time it will just be glaringly wrong in the eyes of the reader.
Also, I still find it hilarious that in an article where you're trying to show how to do CSS "right", I can't read half the text on your page without maximizing my window! That's comedy gold, that is. All the text in your right column overlaps your main body text, making it an illegible mess!
Oh, and here are some more bugs: after hitting Submit (wherein it bitched at me about not closing P tags, WTF kind of bondage and discipline crap are you into here, man?) hitting the Back button cleared out the whole form, so I had to re-type this entry from scratch. Very nice.
Jamie Zawinski - 28th May 2003 22:21 - #
I took my LJ style and recoded it pixel for pixel as non-tables for use with my website. And apparently LJ stole it from Blogger. And Blogger got it from wherever. I'm not sure, but I think if you pay for LJ you get to edit the template like you do for Blogger, in which case I might pay just to not have to use those damn tables. And then I could use a stylesheet switcher on my LJ.
The point was that I did exactly this with my LJ (hotabay) and the result can be seen in my mozblog (linked right below this.)
alanjstr - 29th May 2003 15:08 - #
ratchetcat - 30th May 2003 17:08 - #
mab - 31st May 2003 01:18 - #
Jamie Zawinski - 31st May 2003 11:42 - #
I'm using Mozilla 1.3, and *everything* displays fine for me.
Andrew Hayward - 1st June 2003 00:38 - #
I'll echo the comment on the use of the Universal Selector (*). You could also use it for the
div.entry psituation so that if some later blog entry includes (say) blockquotes, lists, images (etc) then they too would have the requisite padding.In testing this though I find you would need to firstly specify it as
div.entry > *otherwise the margin gets applied to both the first paragraph and also the <a> contained within, bumping it out of alignment.Secondly, you'd need to demonstrate the specificity thing again with the h2 rule:
div.entry h2Thirdly, there's probably other things that will get bolloxed up ... more grist for the tutorial mill :-)
Eric - 2nd June 2003 07:45 - #
deizel. - 4th April 2005 11:33 - #