Some problems with CSS implementations, and a workaround

Note: this document contains a few worthwhile observations together with some out-of-date suggestions (it's not been revised significantly since late 1997). Pending a thorough revision, take it with a grain of salt. For the latest on dodging CSS bugs, see The Verso StyleServer.

This page documents a few serious discrepancies between implementations of Cascading Style Sheets (CSS) in Netscape 4.0 (Mac and Windows) and Internet Explorer versions 3.0.x and 4.0b1. It assumes you understand a good deal about CSS already, but may not yet have attempted to make it work across implementations (including operating systems). It also suggests a workaround strategy (complete with sample code), which may regrettably be necessary in order to use CSS in more than a trivial way on the open Web.

Perhaps the most common "hacks" practiced in HTML on the Web aim to gain control of whitespace, especially vertical whitespace (inter-element spacing, leading, etc.). The HTML header and paragraph elements have been replaced among visually-oriented web authors with combinations of <font> tags, line breaks, spacer GIFs, and non-breaking space characters. There is also a strong tendency to make images of text, for the sake of assuring a special typographical character. These are essentially unfortunate ideas - a point I will not argue here. CSS should make it possible to abandon these hacks and use standard HTML. Unfortunately, CSS implementations make this difficult.

Getting on with it

Here's a rendering I attempted to achieve with standard markup and CSS for a particular window size (just layout - ignore color. Assumes you've got the free cross-platform font Verdana installed.) Note that the space between paragraphs equals that between lines. Note also the character of the font Verdana at this particular size (rendered on a Macintosh at 11 points/pixels).

Here is the live HTML/CSS of my best attempt to realize this rendering in Netscape 4.01(Win32). Please see the source of the referenced document to see what's going on. This was ultimately a failed experiment, so I have left things messy for your analytical enjoyment.

Renderings of the above in the four major "CSS-enabled" browsers.

What's going on

If you specify zero (vertical) margin on consecutive elements, IE takes the line-height specified on the contiguous elements as the actual margin. Netscape, in contrast, discards the line height for the first line and sets the margin to zero. I believe IE's interpretation is correct, but Netscape has shipped across platforms already, notably on the Mac, where most presentation- sensitive web work is prepared. This document shows an attempt to cater to Netscape's interpretation, and reveals many annoying discrepancies between typographical and linear measures, especially across platforms.

There are many more grave discrepancies than shown here - if it wasn't so sad, it would be funny. By rushing out such dangerously substandard CSS implementations, the browser vendors threaten to negate even their future, more conscientious CSS implementation work. A remedy is to use scripting languages to serve separate stylesheets to different implementations. This is unfortunate because it might let browser vendors shuffle their responsibility onto web authors indefinitely, because fixing the bugs will break the workarounds. I think that's better than the alternative of letting CSS rot in developers' perception as a hopeless mess, however. A better use than hacking around bugs is simply to withhold CSS from dangerously substandard implementations, effectively permitting their "boycott," all without penalizing users by withholding content.

By all means, report all CSS bugs you find to their owners, via their bug-reporting pages (Netscape, Microsoft). Of course they've heard it before, but it must help prioritize things if they hear whole choirs of complaint.

Insert the following in your document head and modify as necessary:


<SCRIPT> <!-- // scripting language is deliberately ambiguous
		
//	if IE 4 or later... then get this stylesheet (IE3 for Windows gets confused with straightforward check, hence the contorted logic :

	if ((document.images) && (navigator.appName != "Netscape") && (navigator.appVersion.indexOf('Mac') == -1)) 
	{
	document.writeln("<link rel=\"stylesheet\" type=\"text/css\" href=\"mypath/ie4.css\">")
	};

//	if Navigator 4 and Macintosh (1 point = 1 pixel)... then get this stylesheet:

	if ((navigator.appName == "Netscape") && (parseInt(navigator.appVersion) == 4) && (navigator.appVersion.indexOf('Mac') > 1))
	{
	document.writeln("<link rel=\"stylesheet\" type=\"text/css\" href=\"mypath/macns4.css\">")
	};

//	if Navigator 4 and not Macintosh (1 point = 1.25-1.5 pixels)... then get this stylesheet:

	if ((navigator.appName == "Netscape") && (parseInt(navigator.appVersion) == 4) && (navigator.appVersion.indexOf('Mac') == -1)) 
	{
	document.writeln("<link rel=\"stylesheet\" type=\"text/css\" href=\"mypath/winns4.css\">") 
	};

//	if neither IE nor Navigator... then get this stylesheet (don't lock out the underdog!):

	if ((navigator.appName != "Netscape") && (navigator.appName != "Microsoft Internet Explorer"))
	{
	document.writeln("<link rel=\"stylesheet\" type=\"text/css\" href=\"mypath/default.css\">") 
	};
// -->
</SCRIPT>

<!--eliminates script-language dependency for CSS -->

<noscript>
	<link rel="stylesheet" type="text/css" href="mypath/default.css"> 
</noscript>

Usage notes

Feel free to use, modify, or redistribute this code. Suggestions for improvement encouraged. Comments to Todd Fahrner.

Postscript: a better idea

A few months after writing the above, a new, simpler strategy comes to mind: write complete stylesheets using the spec and best available implementation as guides. Before linking documents, separate out the (small) set of "safe" features into a primary stylesheet. Reference the remaining "unsafe" set from the primary via @import. IE4's the only significant browser I know that will get the secondary sheet. If necessary, include IE4 "crutch" code in the secondary via XSSI. If enough people do this, perhaps it will serve as a discouragement to vendors to release more flaky implementations.


Agitprop