My first CSS was kludgey because I was trying to make it work
well with the hideously defective Internet Explorer 3 and Netscape
4. These days I just try to keep most of my CSS out of those
browsers. Basically all you can feel safe setting on IE3 or
Netscape 4 are the following:
- Colors, in hexadecimal (probably named colors will be OK too,
as long as you stick to the standard 16)
- Font families (IE3 has some problems with this, but they mostly
involve just falling back to the default)
- Some font styles
- Percent left and right margins on
BODY (but not on
anything else)
That's really about it. Just about everything else is broken in
some horrible way. Most things will at least leave your page
readable in Netscape 4 (unless you try to print it out!), but this
is not the case with IE3.
Now, the usual cunning Webmaster's approach at this point would
be to sniff on the user-agent string and serve different styles to
different browsers, either through JavaScript on the client side,
or with some sort of server-side include. However, I don't like
these approaches very much; they seem overly complex and fragile,
they are notorious for being tripped up by the introduction of new
Web browsers, and I find repugnant the idea that I should have to
mess with scripting or the back end just to get some CSS to
work.
Instead, I use a trick that is apparently due to Todd
Fahrner, though I learned it from Matthew Brealey. I
have a very simple style sheet for IE3/Netscape 4, and a much
longer one for other browsers. The first style sheet fetches the
second one via @import. IE3 and Netscape 4 don't
support this, so they will only see the first sheet. I can do fancy
stuff in the other sheet and not worry about it breaking the
terrible two. Apart from them the worst widely used CSS browser is
Internet Explorer 4 for Windows, but the problems in that are
much easier to deal with.
The only problem is that there are some very early Netscape 4
versions (pre-4.08) that crash when they encounter
@import in a style sheet! These versions are so
unstable that most Netscape 4 users upgraded long ago, but it's
something to keep in mind. Really the only alternatives are to do
something even kludgier like JavaScript or server-side browser
sniffing, or to avoid using about 90% of CSS.
I've heard people complain that this method is now obsolete
since Netscape 6 supports @import. These people are
missing the point. It's good for this method that Netscape
6 supports @import, because Netscape 6 also does CSS
correctly.
Top
New problems
Given how good things were getting with recent versions of IE
(especially IE/Mac), Netscape 6/Mozilla, and Opera, I had reason to
believe that CSS authors were out of the woods: developers had
learned their lesson and new browsers would come out with
relatively solid CSS support if they had any at all.
Unfortunately this appears not to be the case, and the
frustrating thing is that some of the problems are associated with
browsers I think of as good guys for other reasons. I like iCab,
for its customizability, its brilliant "smiley face" that validates
HTML on the fly, and the support of some HTML 4.0 features
supported by almost nothing else. I very much like OmniWeb 4,
simply because it has the best integration into Mac OS X of any Web
browser, and is also quite customizable in ways that give
tremendous power to the user.
Both OmniWeb and iCab have recently released partial CSS1
implementations, and, sadly, both of them have Netscape 4-like
defects with critical things like margin calculations that can ruin
page layouts. OmniWeb's implementation seems less complete, which
also limits the damage that bugs can do. However, OmniWeb has a
serious omission: there is no off switch yet for author CSS, which
makes it harder to deal with the problems that do occur.
I'm adopting a wait-and-see attitude toward these
implementations. Software development is hard, especially for
functions as complicated and subtle as those implied by even the
CSS1 recommendation. In both cases, the authors freely admit that
the CSS support is incomplete and needs work, and they seem to be
working hard on it. This isn't a Netscape 4 situation in which the
bad implementation is obviously going to be widely used for a long
time to come. Therefore, I'm not going to tinker with my pages just
to make them look good in those browsers.
I do think that both OmniWeb and iCab should have taken the
approach that iCab wisely followed with its JavaScript
implementation: make it user-switchable and leave it turned
off by default until the support is really good.
Unfortunately this was not done with CSS, which makes it an issue
for page authors. My hope is that people using these promising
browsers are savvy enough to understand the situation.
(Note added April 2002: OmniWeb has become popular among Mac OS
X users, and deservedly notorious for what's become known as the
worst CSS support on the platform. Version 4.1 beta 2, though,
improves the situation considerably. It's still got a long way to
go. I'd say that it's gone from a Netscape 4-like level of support
to something more comparable to IE4/Windows. But it's definitely
now better at CSS than iCab, whose buggy box model implementation
is responsible for the gigantic margins and drunken line spacing
visible on many of these pages. On the other hand, iCab does let
you turn off CSS.)
(Note added November 2003: Things are looking up. The latest
version of OmniWeb uses the WebCore layout engine built for Apple's
Safari (which in turn is based on Konqueror's KHTML component).
This is not quite up to the level of Mozilla's Gecko, but is very
close. Meanwhile, Safari itself has captured an enormous chunk of
the Mac market, and Gecko-based browsers and IE/Mac have much of
the rest; the less standards-compliant browsers are also-rans, and
the rise of Mac OS X seems to have finally put an end to Netscape
4.x's reign as a leading Macintosh browser. Good times.
Unfortunately, IE6 on Windows isn't quite as much of an improvement
over IE5 as it should be, but you can't have everything.)
Top
Text
Text and background color
I've gone for high contrast throughout, not just to help people
with color blindness and low vision but to help people with normal
vision too. Whether they realize it or not, nobody has an easy time
reading text with low brightness contrast, and the brightness
differences between Mac and PC displays, and between displays with
different settings viewed under different conditions, make it all
the riskier to try.
The general rule with Web color is that if you set a
background color for something you should set a foreground color as
well, and vice versa, so as to avoid bad interactions with user
settings. So I'm stuck with trusting browser color settings (which
sometimes default to ugly gray backgrounds, and which users have
gotten used to not changing because most pages do it) or actually
making color choices. As a tinkerer I naturally end up setting the
colors.
Whether dark-on-light or light-on-dark text is easier to read is
something that provokes passionate arguments. What the participants
often fail to notice is that the light-on-dark proponents are
frequently working in dark basements and the dark-on-light fans in
brightly lit offices. (Old-school hackers tend to like dark rooms
in part because in the olden days all video display terminals were
light-on-dark. I know guys who specifically request the disabling
of all lighting over their cubicles because they like
green-on-black text windows.) In general, you want the brightness
of your display to be comparable to that of the display's
surroundings. I've chosen black on white because I prefer it and
because it is somewhat less likely to interact badly with the
default settings of most Web browsers.
I depart from the mostly monochrome scheme for non-link colors
for the case of BLOCKQUOTE elements that are used to
indicate Usenet quoted text. To make it easier to follow
complicated multiply-nested conversations, I use alternating brown
and dark green coloring for the nesting levels. This was inspired
by the behavior of some newsreaders that color quoted text
differently.
Top
Font
However, I do not set the font family or font size used
for ordinary paragraph text. This makes it as easy as possible for
users to adjust these things if they find my text hard to read.
Other font sizes are set in relative units so that they will
rescale even in Internet Explorer versions that don't let you
rescale absolute-sized text. Thus I sidestep the whole PC vs. Mac
vs. Linux font-size problem, adapt gracefully to people with low
vision, and generally make people happy. If the font looks too big
or too small, just change it.
Top
Headings
The gray "outdented" headings, and the right-aligned subtitles
that match them visually, were one of the earliest CSS tricks I did
on these pages, when I was working with IE3 and Netscape 4. Now the
outdenting is not even visible on those browsers, because I moved
that effect to the imported part of the style sheet, for various
reasons. I was just trying to do something a bit unusual yet
dignified-looking; I may have been partly inspired by the Lynx
treatment of H2 and higher. Since then, outdented
headings have become a common thing on Web pages that use CSS. You
can indicate a hierarchy with them easily, and their inherent
asymmetry can be attractive if the page is laid out in a balanced
way.
When text is big, you can get away with more. Originally I had
three different shades of gray that got progressively lighter for
H1, H2, and H3 elements. I
cut it to two to make absolutely sure that I didn't lower the
contrast too much for headings that were going to be pretty small.
I still think the use of two shades of gray looks nice.
On the off chance that you've got Gill Sans installed, the
headings are in Gill Sans, which is one of my favorite display
faces. Most people will probably see them in Verdana, a font that
is in some ways similar and is a fine font in its own right.
The right-aligned subtitles are actually a class of paragraph,
not a heading (from a structural perspective this is probably the
best way to handle them). I also have a special class called
impactor that I use to make some short
H1s larger than usual. Originally the
H1.impactor was truly gigantic ("impactor" meant "make
this like unto a dinosaur-killer asteroid"), and I used it mostly
for comic purposes, making a word or two fill half of the screen.
When it was pointed out to me that font sizes that big could
actually crash some browsers, I toned it down, which also made it
more useful. It's still pretty big.
Top
Links
For now I've chosen blue unvisited and dimmer purple visited
links because those colors are familiar and understood by most
users.
There seems to be a general consensus today that Jakob Nielsen
is wrong and you can use whatever link colors you want. I agree
with that more or less, but I do think that some possible choices
are not good, like making them all the same color as the text, or
making them unreadable against the background, or choosing colors
such that the visited links look like they ought to be unvisited
and vice versa. One page about CSS at the W3C used to use
purple for unvisited links and blue for visited ones! (It's fixed
now.)
Underlined vs. non-underlined links are another controversy.
People with a typographic background tend to find underlines
unbearably hideous, and they are almost never used in books. So the
first thing these people do when making a Web page or setting up
their own browser is to ask how to get rid of link underlines.
Personally I think that the fact that underlines are not
used in ordinary typography makes them splendid as a choice to
indicate something that never appears in print, like a hyperlink.
They're also another level of color blindness support.
I've decided simply to not specify anything about link
underlining. It's up to the user.
The hover effect is a pure affectation. I doubt that it does
anything good from a usability perspective but it looks cool
without doing any real harm. For a long time, I did these hover
effects using CSS2 dynamic pseudo-class combinations such as
A:link:hover. I had to make them rather subtle because
of a bug in Opera that applies such styles to all links, not just
the hovered ones. (This is sometimes claimed not to be a bug, since
Opera makes no claim to support dynamic pseudo-class combinations.
However, in this case it is still a bug in Opera's error handling:
it should ignore unsupported selectors rather than applying them
wrongly.)
Recently I've given up any hope that this will ever be fixed in
Opera, and reverted to the stupid old A:hover method,
which allows me to make the hover effect a little more overt, if
less versatile.
Top
Margins and layout
Right and left margins
My margins have evolved over time, gradually getting larger and
larger. There's a certain design tension here. On the one hand it's
traditionally considered detrimental to make text too wide, and
many, perhaps most people read the Web with a full-screen browser
window. This leads to a temptation to set the text width.
On the other hand, the CSS methods supported by most of today's
browsers only let you set widths either not at all or in a
too-rigid way, so that if the browser window is narrow, it
won't flow to fit.
My compromise is to set generous margins in percent units. The
text still gets a bit uncomfortably wide if the browser window is
wide, but at least there are nice big margins in that case, and if
you make the window narrow the margins shrink to fit.
Then, for the few, very modern browsers that support it
(Mozilla/Netscape 6 and Opera, for instance), I use the CSS2
max-width property on paragraphs and similar things,
set in ems, to limit how wide the paragraphs can get relative to
the font size. I use max-width, not
width, so that the text will flow to fit a narrower
window if necessary.
The margins on BODY are about as large as they can
be given a problem with "outdented" page elements. While the
correct behavior of percent widths in CSS is to calculate them with
respect to the containing block, in Internet Explorer 4 and 5 on
Windows they are instead calculated with respect to the browser
window, and in OmniWeb they are calculated with respect to the
whole screen. This can lead to the "outdenting" pushing things
right off the page if percent widths are used. So I have to tone
down the use of negative margins on headings. The narrower
BODY is, the more of a problem this becomes, because
the difference between the various calculations becomes larger.
Top
Into the margins
(Note added September 2002: Much of the following section is now
obsolete, because an infuriating bug in Internet Explorer 6 for
Windows tends to amputate things with negative right margins, and
I've had to get rid of most of them.)
I've already mentioned the "outdenting" of the headings to
varying distances into the left margin. This looks nice and
illuminates the structure of the document, but its asymmetry leads
me to want to balance the page composition somehow. Consequently
there are things that extend toward the right as well.
The most obvious are the page navigation header/footers, whose
borders extend to the right but not to the left. Originally
(because they date from my very earliest Web pages, written when
nobody knew better) these things were just raw text and links in
the body of the page, set off by horizontal rules below the headers
and above the footers. I wanted the horizontal rules to extend some
distance into the right margin but to end abruptly at the left
margin. This looked smart when it worked, but it turned out to be
extraordinarily difficult to achieve because of the wildly varying
renderings of horizontal rules in different CSS-supporting
browsers. In particular, I could never get the things to end at the
left margin in Internet Explorer on Windows, no matter what I
did.
When Netscape 6 would do what I wanted in bugwards-compatibility
mode but not in correct-rendering mode, I began to suspect that I
was approaching the whole issue incorrectly. I had been a bit
nervous anyway about the possibility of future problems with having
unenclosed text in BODY. So I took out the horizontal
rules and made the headers and footers into a class of
DIV. I could have gotten my original design by making
two classes and putting bottom borders on the headers and top
borders on the footers, but decided to change the look a little
instead.
I was going to give them a different background color but
couldn't find anything in the browser-safe palette that satisfied
me (the lightest gray was still too dark for a good-looking
background, and the paler colors all clashed with the rest of my
design).
The varying thicknesses are reminiscent of musical notation, and
also evoke a vaguely embossed effect while not being too literal
about it (as the 3D border styles would be). I use different border
styles on the pages that are supposed to look different, such as
the blue-sky pages and the Kibology index page.
I also have right-floating images that extend into the right
margin, and right-floating links back to tables of contents.
Because I use negative percent margins on things enclosed in
BODY, I've had to moderate the extent of right
floating somewhat to get around problems that Internet Explorer
4/Windows has with calculating percent margins (they tend to be
calculated with respect to the browser window rather than the
containing block). I also have to limit my use of these somewhat
because of a strange bug in IE5/Mac that can mess with the margins
of paragraphs in a DIV that flow around a floating
element defined outside the DIV, but with some care
this is not much of a problem.
Top
Paragraphs
From my earliest CSS days I've flirted with book-style indented
paragraphs. This is another controversial issue. The W3C actually
tells you not to use them, apparently on the philosophy that
indentationless paragraphs with wide inter-paragraph leading are so
familiar on the Web now that anything else would be confusing. I
don't actually believe this, in part because so many commercial Web
sites do other kinds of paragraph formatting in various ways.
The traditional rule among typographers is that you should have
extra space between paragraphs or indented first lines,
but not both, and in early, bad CSS implementations I couldn't get
rid of the extra space between paragraphs. For a while I had
considerable amounts of extra leading and indentation on
first lines, until a typographer friend told me to stop it.
When I finally could do what I really wanted (at least
on newer browsers), it turned out that the traditional book
formatting-- about an em of indentation, and no extra leading--
made paragraphs a bit hard to distinguish on-screen, maybe because
the paragraphs could be so wide on a wide window, maybe because of
the extra general difficulty of reading things on CRTs as opposed
to print. The first-line indentation also messed up a lot of things
that I did with isolated paragraphs, and there was annoying extra
markup I had to do to get around that.
Eventually I came up with something that seems to work pretty
well; it involves a small amount of extra markup, but the markup is
more or less structural rather than pure hackery. My
default paragraph formatting has no first-line
indentation, and substantial leading between paragraphs. However, I
also have a special DIV.text class which signals a
region of book-like text. Within such a DIV, there is
paragraph indentation (a bit larger than you usually see in books),
and a much smaller, almost subliminal amount of extra leading
between paragraphs, just to give the reader a little more help
seeing the paragraph breaks.
DIV.text itself gets generous vertical margins,
smaller on top (so that headings are visually grouped with
succeeding DIVs) and bigger on the bottom, so that I
can use these blocks to group text into sections separated by more
white space. I also use the CSS2 :first-child
pseudo-class to eliminate the indentation on the first paragraph of
one of these DIVs. This is not universally supported,
but it really doesn't matter much if it isn't.
The markup gives me a considerable amount of flexibility to
change my text formatting in the future if I want to.
More out of a will to tinker than anything
else, I use the float property and :first-letter
pseudo-element to do a drop-cap effect, that is, a giant floating
first letter that visually matches the H1 headings. A
little of this goes a long way and it can be silly-looking if
overused, so there's a special paragraph class for this sort of
thing and I only use it infrequently, if at all, on any given
page.
The vertical formatting that I get for these drop-caps is
different on Internet Explorer and Mozilla/Netscape 6 (something to
do with variations in the handling of extra space to allow for
accent marks). For a while I had the styles tweaked to make the IE
rendering as good as possible, but the result was unacceptable on
Mozilla, so now it's tweaked the other way, which is not quite so
bad-looking on IE (also the CSS coding is more logical this
way).
I've experimented with using :first-line to put the
whole first line of such a paragraph in small caps, but this has
certain small but annoying glitches on IE5/Mac (links in the first
line end up disguised as plain text until the mouse rolls over
them, for instance). I'm not sure it's such a good idea for these
pages anyway. A better thing from a traditional typography
perspective would be just to do the first few, carefully chosen
words in small caps, but that necessarily involves more markup, and
at this point my laziness kicks in.
Top
Lists
List formatting has been a headache for me for some time. I
think I've finally got it right. In my earliest CSS days I put
margins on individual text block elements instead of on
BODY, so lists presented a particular problem: if I
gave lists or list elements a substantial left margin, nested lists
would use multiple copies of the left margin and come out all
wrong. So I stayed away from setting list margins, and lists tended
to be shoved up against the left edge of the window even when
paragraphs weren't. (I think I tried using descendant selectors to
fix this and had trouble getting them to work.)
I eventually figured out that margins on BODY would
sidestep that problem, but there was still a baffling
Netscape/Internet Explorer difference: I could set the indentation
by messing with margins on IE but they seemed to be added to the
default on Netscape 4. I just chalked it up to another Netscape 4
bug and lived with it until I discovered how to exclude styles from
Netscape 4.
Then I discovered that the same thing was happening in Netscape
6. Obviously I was missing something.
Then I read a Usenet post by David Baron that explained
everything. It has nothing to do with the rendering of CSS itself,
but rather with the default user agent styles that produce the
default list rendering. I'm not sure about Netscape 4, but by
default, Mozilla/Netscape 6 implements list indentation as
padding, whereas Internet Explorer implements it as a
margin. I was changing the margin without doing anything
to the padding, so on Netscape 6, its default padding and my margin
added to increase the list indentation over what I
expected.
So if you want to play with the size of list indentation on
UL or OL, you have to explicitly set both
the left padding and the left margin. You can just set one to zero
and use the other one. It doesn't matter which you use under
ordinary circumstances, though in more complex cases you might
actually care about the difference between margins and padding (it
will make a difference for things like borders and special
background colors on sub-lists, for instance).
I also put tiny vertical margins on inner nested
ULs and OLs, which produces a subtle
grouping effect that I like.