Tutorials Bugs Masterclass Free stuff Test pages Proposals

RichInStyle.com - Style sheet master class: part 3 - cross-browser style

Contents

Part 1 - Introduction

Introduction

Decision time

Embedded style sheets?

Part 2 - Making them work

Section A - One style sheet for all browsers

Section B - One style sheet with hacks for each browser

IE 3 hacks

IE 4 hacks

Opera hacks

Netscape hacks

Section C - Separate style sheets for each browser

Creating the style sheets

Conclusion

The method used by RichInStyle.com

Part 1 - Introduction

Introduction

So you've got your perfect style sheet, and you've coped with the older browsers. Now you're wondering, 'How do I fix my styles so they work with all the newer browsers?'.

The answer is that it is a lot easier than you probably imagine - provided you've fixed your style sheet according to the principles laid down in RichInStyle.com's guide to creating perfect style sheets, your task is not a large one. If you haven't done this, do it now.

The best way to do things

You might think that your first decision is as to which of these routes you wish to take:

  1. If you use LINKed style sheets:
    1. Do you want to have one style sheet that will work with all browsers and will be limited in terms of styles by this fact, or
    2. do you want to have one style sheet that uses hacks to apply different style to different browsers, or
    3. do you want to have a separate style sheet for each browser, with the total freedom this entails?
  2. If you need embedded <STYLE> sheets:
    1. Do you want to have one style sheet that will work with all browsers, and be limited in terms of the styles that you can use by this fact, or
    2. do you want to have one style sheet that uses hacks to apply different style to different browsers?

But in fact I believe the decision makes itself: you should use a style sheet with hacks. If you are careful the hackarounds will mean that each browser looks perfect.

Embedded style sheets?

The next decision that you will need to make if you use LINKed style sheets is whether you wish to add a short embedded style sheet to your page to ensure that the essential elements of your pages' design are retained when your page is read offline.

This is only an important consideration if your pages' nature is such that they are likely to be read offline. If you feel that the number of people that will do this is significant, to simulate the offline experience, simply view the page without the LINKed style sheet. If you are happy with what it looks like, there is nothing further for you to do. If not, you will need to add an embedded style sheet to your page.

This shouldn't contain more than three or four essential rulesets. Generally, I find that these are BODY's characteristics, plus fonts. For example, on this page I specify:

<STYLE type="text/css">
<!--
BODY {margin-left: 8%;
color: black;
background: white;
margin-right: 6%}

BODY, H1, H2, H3, H4, H5, H6, TD, TH, DIV, PRE, CODE, SPAN, P, OL, UL, DL, DT, DD, LI, BLOCKQUOTE {font-family: Arial, Helvetica, sans-serif}

SPAN.richinstyle {font-family: "Comic Sans MS"}
-->
</STYLE>

The one difficulty that you will face is the need to avoid browser bugs, since certain of your styles may be affected by bugs in certain browsers. To avoid this, see the section below on this topic.

There is but one important reminder while on the subject of embedded style sheets, however, and that is this: the embedded style sheet must precede the LINKed one so that you don't have to make changes to each embedded style sheet when you change your LINKed style sheet.

So this is what your template looks like so far:

<HTML>
  <HEAD>

<!-- The STYLE block is optional; see above -->
    <STYLE type="text/css">
      <!--
        /* You must include the comment delimiters (<!-- -->) to avoid style appearing on screen in Netscape 3 et al. */
      -->
    </STYLE>
  </HEAD>
  <BODY bgcolor="#xxxxxx" text="#xxxxxx" alink="#xxxxxx" vlink="#xxxxxx" link="#xxxxxx">
      <!-- These (bgcolor, etc.) are from RichInStyle.com's old browser page; change them to your preferred colors -->
  </BODY>
</HTML>

The method used by RichInStyle.com

The method that RichInStyle.com uses to serve style sheets is this: it uses the following HTML:

<HEAD>
<STYLE type="text/css">
<!--
BODY {margin-left: 8%;
color: black;
background: #fff;
margin-right: 6%}

BODY, H1, H2, H3, H4, H5, H6, TD, TH, DIV, PRE, CODE, SPAN, P, OL, UL, DL, DT, DD, LI, BLOCKQUOTE {font-family: Arial, Helvetica, sans-serif}

SPAN.richinstyle {font-family: "Comic Sans MS"}
-->
</STYLE>
<LINK rel="stylesheet" href="/style/all.css" type="text/css">
<SCRIPT language="javascript1.2" src="/style/MySite.js" type="text/javascript">
</SCRIPT>
</HEAD>
<BODY bgcolor="#FFFFFF" text="#000000" alink="green" vlink="red" link="blue">

The small STYLE block is for people that view pages offline - this provides an acceptable subset of the full browsing experience. Note that the styles chosen are all non-problematic so that there is no chance of any problems.

Next comes the linked style sheet. This contains the full style experience. It looks like this:

@import url(okbrowsers.css);
Stuff for incompliant browsers goes here; the style for proper browsers goes in okbrowsers.css

Last, but by no means least, comes the MySite script. This remembers the style that the user prefers and uses it. If you want MySite technology for your site, you should click here.

Making them work

As a general principle all style sheet users should either

  1. keep their style sheet in the same directory as their HTML in order to avoid problems with background images in Netscape, or
  2. make style sheet references relative to the top of the domain by starting with a '/'; e.g., BODY {background: url(/images/image.jpg)} to ensure that Netscape doesn't cause any problems.

Section A - One style sheet for all browsers

If you've chosen this option, you've selected the easiest of all the methods of ensuring that your page looks o.k. on all browsers. However, you have also selected the method that limits your creative freedom to the greatest extent.

For example, you can't make use of line-height or margin-top declarations.

There are far too many bugs to list here, but here's a quick guide:

  1. Avoid margin-top.
  2. Avoid all units (including %, em, etc.) except pixels.
  3. Avoid specifying line heights.
  4. Do not use the normal keyword on the font shorthand (it is superfluous anyway).
  5. Do not use numerical font weights on the font shorthand.
  6. Set margin-left and margin-right only on BODY.
  7. Avoid all styles on LI, DD and DT.

In addition if you use tables, you will need to separate your BODY selector into two parts: one for inherited properties, and the other for non-inherited properties. For example:

BODY {font-family: sans-serif;
color: red;
background: white;
margin-left: 7%;
margin-right: 5%;
margin-bottom: 2em}

Becomes:

BODY {font-family: sans-serif;
color: red}

BODY {background: white;
margin-left: 7%;
margin-right: 5%;
margin-bottom: 2em}

Next, add every block element except for LI, DD and DT, plus SPAN to the inherited ruleset:

ADDRESS, BLOCKQUOTE, BODY, DIV, DL, H1, H2, H3, H4, H5, H6, OL, P, PRE, SPAN, UL {font-family: sans-serif;
color: red}

The reason that this is necessary is that Netscape 4 and Internet Explorer 3 are very badly buggy and when they encounter a table, the usual result is the termination of BODY's style for the table and all subsequent content.

Note that this is only a very brief guide, but it should help you on your way to bug-free style. If you want to see a sample style sheet converted to a suits-all style sheet, you can do so, but you should take a look at the rest of the master class first.

Section B - Hacks to hide style from browsers

This section is pretty similar to the last one, except it aims to be more adventurous in terms of what it achieves. The essence of this section is the exploitation of the browser bugs in order to hide style from certain, or else to only apply style to certain browsers.

Generally, the browsers that cause 99% of the problems are Internet Explorer 3 and Netscape 4. In view of this fact, it is useful to have methods that will hide styles from these browsers.

The principal method to exclude Internet Explorer 3 and Netscape is:

/* This is a style sheet */
@import url(okbrowsers.css);

Stuff that works in all style sheets goes here; all other styles go in okbrowsers.css.

If these aren't enough, here are some more hacks to hide styles from each of the browsers (note that many of these are invalid CSS):

Internet Explorer 3

  1. Include element_name#id as part of the selector to hide from IE 3 - DIV#body P {line-height: 1.2} will hide the declaration from IE 3 (#body P wouldn't).
  2. Use multiple LINKed style sheets - in IE 3 for Windows, all but the last will be ignored. For example:

    <LINK rel="stylesheet" href="WillNotBeReadByIE3.css" type="text/css">
    <LINK rel="stylesheet" href="awayie3.css" type="text/css">

    Awayie3.css must contain at least one non-whitespace character; for example, if you just put .dummy {color: red} in it, it would hide from IE 3.

  3. Include hyphens inside classes or IDs.
  4. Use LINKed style sheets with embedded ones - in IE 3 for Windows, the embedded one will be ignored. For example:

    <STYLE type="text/css">
    /* Won't be read by IE 3 */
    </STYLE>
    <LINK rel="stylesheet" href="awayie3.css" type="text/css">

  5. Precede a declaration to be hidden by a one line @rule; for example, @cheese "bah"; .hidden {}.
  6. Use embedded style sheets - in IE 3 for Windows, all but the last one will be ignored.
  7. Have the property immediately followed by a comment; for example, color/* comment */ : red.
  8. Where the same property is specified on an element in several different declaration blocks, IE 3 ignores all but the first:

    P {color: red;
    font-size: 14pt}
    P {color: green}

    This would make P red, because the redeclaration is ignored (though P {color: red; color: green} works correctly).

    Thus for each of IE3's buggy properties it is possible to have one declaration for IE 3 and one for everyone else. E.g.:

    BODY {color: black}
    BODY {color: white;
    background: black}

    In normal circumstances this would cause major problems because IE 3 doesn't support background on BODY in LINKed style sheets. In this case however, the fact that the color is white won't clash with IE3's background because it ignores color: white and applies color: black instead.

  9. Include a comment inside a simple_selector; for example, P/* comment */.class
  10. Enclose style in @media all {} (or @media screen). This will only hide the first ruleset from IE 3, and also requires a subsequent .dummy {}; for example, @media all {.hidden {} .nothidden {} } .dummy {}
  11. Link styles via @import - IE 3 doesn't support @import.
  12. Omit the HTML or BODY tag and declare styles using the HTML/BODY selector
  13. Use the backslash to hide - P \{ {color: red; background: green} hides from IE 3, but not from compliant browsers (at present only Mozilla 5 fits the bill).

Internet Explorer 4

  1. Use the string format of @import instead of the url() format; for example, @import "hiddenfromie4.css"; would hide it from IE 4.
  2. Follow the property by a comment; for example, color/* */ : red
  3. Use @import with a medium - e.g., @import url(hiddenfromie4.css) screen;
  4. To apply only to IE 4, P/* comment */ .class {}

Internet Explorer 5

  1. Follow the property by a comment; for example, color/* */ : red

Opera

  1. Apply style via an @import that doesn't precede all rulesets; for example, P {} @import
  2. Add a class or id to BODY and add this to the selector; for example, BODY.class P {hidden}
  3. Use P, {}. Note that this is valid CSS, since simple_selector is partly defined by element_name?
  4. Use a case-insensitive match of a class or id; for example, with <DIV id="body">, #Body P to hide them from Opera
  5. Have style in an @imported style sheet specified for screen (not all) specified in a position other than first in a list; for example, @import "hidden.css" madeup, screen;
  6. Enclose the property value in quotes; for example, color: "red"
  7. Use a ' as a fake identifier character to hide everything that follows it from Opera; for example, P.dumm'y {}
  8. Use the SGML comment open tag on the same line as a selector to hide the declaration from Opera - e.g., <!-- P {color: red} (note that there must not be a line break before the selector)
  9. Use the backslash to hide from Opera - P \{ {color: red; background: green} hides from Opera
  10. When specifying in pixels, omit the px to hide the declaration from Opera; for example, margin-top: 12 [note this only applies to box model properties - on font-size and line-height, it hides from Netscape as well].
  11. Omit the # from colors to hide from Opera

Netscape 4

  1. Use !important - Netscape ignores it; for example, P {color: red !important} P {color: blue} would apply blue in Netscape (and IE 3 (although for a different reason - IE 3 ignores the whole declaration (provided the property takes as its value a single identifier), Netscape just the !important bit)) and red in IE 4-5 and Opera
  2. Enclose style in @media all {} (or @media screen)
  3. If specifying font-size in pixels, omit the px to hide from Netscape; for example, font-size: 12
  4. Have a line break between the ! and the important to hide the whole declaration from Netscape
  5. Add a fake @rule to a ruleset to hide the subsequent ruleset from Netscape - .dummy {color: @hello {}; color: red} .hiddenfromnetscape {color: red}
  6. Use the backslash to hide from Netscape - P \{ {color: red; background: green} hides from Netscape
  7. Link styles via @import - Netscape doesn't support @import
  8. Designate the style sheet as for media="all" (e.g., <LINK href="css.css" rel="stylesheet" type="text/css" media="all"> ;<STYLE type="text/css" media="all">) - this will hide it from Netscape
  9. Include a comma in the media declaration, e.g., media="screen, all"
  10. Apply styles using the HTML selector - Netscape doesn't support it
  11. Include element_name#id as part of the selector to hide it - DIV#body P {line-height: 1.2} will hide the declaration from Netscape (#body P wouldn't)

Section C - Separate style sheets for each browser

Having decided on this option, you need a script to serve the right style sheet on your users.

However, you will also need a style sheets for users who aren't, for any reason, detected by the script, or who have disabled scripts. This should be a style sheet that works on all browsers.

Next you need an inline script for IE 3 users (since IE 3.0 and 3.01 don't support src). This script must serve one style sheet to users using 3.0 for Windows and one for users using 3.01+ or 3.0 for the Macintosh.

Here's the script (which is 278 bytes long):

ua=navigator.userAgent;
l='<LINK rel="stylesheet" type="text/css" href="ie3';
if (ua.indexOf('IE 3.0')!=-1){
    if (((ua.indexOf('IE 3.0A')!=-1) || (ua.indexOf('IE 3.0 ')!=-1)) && (ua.indexOf('Mac')==-1)) document.write(l+'0.css">');
    else document.write(l+'.css">');
}

The above script is copyright RichInStyle.com 2000. You may only use it within the SCRIPT element of your page. You may modify it, but must not exhibit the source code publicly.

If you wish to know the purpose that the SCRIPT above is serving, it is to allow you to give IE 3 users different margins on different elements - without it you cannot do this, but are confined to only specifying margins on BODY for IE 3 users.

The decision on this matter is entirely yours. However, if you do specify margins on elements other than BODY, then it is only considerate to offer IE 3 users them as well. Therefore, even if you don't need separate style sheets now, I recommend that you retain them (and thus the SCRIPT above) for the future. Without the SCRIPT above, for example, IE 3 users would be faced with the ugly sight of this page without its outdented headings.

The next thing to do is to add a SCRIPT to detect the other browsers. All the other css-supporting browser support the src attribute, and so therefore since the style sheets are being LINKed, you would be mad not to include the script below in an external file (it is 568 bytes long so presents no significant download time):

/* (c) 2000 RichInStyle.com (www.richinstyle.com); you may only use this script in the SCRIPT element of a page. You must not alter or remove this message */
ua=navigator.userAgent;
l='<LINK rel="stylesheet" type="text/css" href="';
c='.css">';
if (ua.indexOf('IE 4')!=-1)document.write(l+'ie4'+c);
if (ua.indexOf('IE 5')!=-1)document.write(l+'ie5'+c);
if (ua.indexOf("Opera 3")!=-1)document.write(l+'op3'+c);
else if (ua.indexOf("compatible")==-1) {
  if (ua.indexOf("/4")!=-1)document.write(l+'nn4'+c);
  if (ua.indexOf("/5")!=-1)document.write(l+'nn5'+c);
}

This script is copyright RichInStyle.com, and although you may modify it, you must not alter or remove the copyright message, and must not exhibit the source code publicly.

Having done this, you now have a template file that looks like this (i.e., you must include the following in your HTML):

<HTML>
<HEAD>

<!-- Optional: -->
<STYLE type="text/css">
</STYLE>

<LINK rel="stylesheet" href="all.css" type="text/css">
<SCRIPT type="text/javascript">
<!--
ua=navigator.userAgent;
l='<LINK rel="stylesheet" type="text/css" href="ie3';
if (ua.indexOf('IE 3.0')!=-1){
    if (((ua.indexOf('IE 3.0A')!=-1) || (ua.indexOf('IE 3.0 ')!=-1)) && (ua.indexOf('Mac')==-1)) document.write(l+'0.css">');
    else document.write(l+'.css">');
}
// -->
</SCRIPT>
<SCRIPT src="style.js" type="text/javascript"></SCRIPT>
<BODY bgcolor="#xxxxxx" text="#xxxxxx" alink="#xxxxxx" link="#xxxxxxx" vlink="#xxxxxx">

Creating the style sheets

There are two approaches that reveal themselves:

  1. Put the styles that work in all.css and use op3.css, ie5.css, etc., to modify it
  2. Make each style sheet individually complete

It would seem initially that the first of these methods is the more attractive. However, a little experience reveals the fact that this is not so. For example, if you could put only color and font declarations in all.css and had to put margin and padding declarations in the browser-specific style sheets, then the task would be much easier. This is not the case unfortunately - it is not possible to include any one property in all.css: color, margin, padding and font all suffer from bugs that mean that you'd have to include padding except for on x and y, or margin except for on a and b. As a result, you should adopt the second approach.

You need to create 8 style sheets, one for IE 3.0 (ie30.css), one for IE 3.01-3 (ie3.css), one for IE 4 (ie4.css), one for IE 5 (ie5.css), one for Opera (op3.css), one for Netscape 4 (nn4.css), one for Mozilla 5 (will become Netscape 5) (nn5.css) and one for all browsers.

If this sounds like an onerous task, do not fret - in most cases, the Opera, Mozilla 5, IE 4 and IE 5 style sheets will be identical, and the IE 3.0 and 3.01-3 all but identical (apart from margin-left declarations). In addition, you are not actually creating separate style sheets, but are merely fixing an existing one.

It is here where the virtues extolled in RichInStyle.com's guide to writing perfect style sheets come into their own. You should ensure that your own style sheet conforms to these guidelines, or else it is likely that you will suffer serious difficulties.

In addition, you should avoid embarking upon the task of fixing your style sheet for the individual browsers until it is finished. This will save much wasted time. If you later find that changes are necessitated, you should ensure that you update all of your style sheets at once.

In order to undertake this process, you will need to take advantage of RichInStyle.com's browser bug guides. However, I strongly recommend that you do not do this until you have read the rest of the master class, since it is probable that you will make changes to it as a result of reading the rest of the master class.

Conclusion

If all this is getting you down, you could just take the easy way out, and just write for Internet Explorer 4 and 5 and Opera. You do this by linking your style sheet via an @import statement.

This will exclude nasty old Netscape 4 and Internet Explorer 3, and save you the bother of working round all their bugs, thereby allowing you to treat them in the same way as non-css supporting browsers. Thus:

<HEAD>
  <STYLE type="text/css">
  @import url(style.css);
  </STYLE>

Note that you must use the url() form of @import, not the string format (" " or ' ' ).

That's the end of this part of the RichInStyle.com guide to cross-browser style; to continue to the next section, click here.