TJKDesign: Home Page

ez-css Putting the 'less' in table-less layouts. css-101 logo
Bookmark this article at these sites:

Say no to CSS hacks with branching techniques.

Branching (also called forking) is a means to serve different styles to different browsers. It can take place within the (X)HTML markup or within CSS files, but most of the time, designers implement filters within the files themselves.

The issue with hacks inside styles sheets

Embedding CSS filters within a styles sheet may:

- invalidate the sheet:
some hacks are "safe", but the validator chokes on more than a few.
- create unecessary declarations:
a declaration that targets a single browser is served to all UAs.
- create redundant declarations:
a same attribute is used more than once with different values (see below).
- create cryptic declarations and rules:
For example, the Box Model Hack looks like this:
div.content { 
  width:400px; 
  voice-family: "\"}\""; 
  voice-family:inherit;
  width:300px;
}
html>body .content {
	width:300px;
}

The solution

By doing the branching inside the (X)HTML markup, it is possible to contain what I call "proprietary fixes" within specific files. The main advantage of this approach is that it dramatically improves maintainability.

Take noteFYI: moving hacks from the styles sheets (the presentation layer) to the (X)HTML markup is considered bad practice by some (a very few).

The workflow

Follow these steps to make your documents 99.99% hack free:

  1. Start with the right DTD. Choose one of the Doctypes below to make sure your documents won't mix presentation markup with structural markup.
    HTML 4.01 Strict:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
    "http://www.w3.org/TR/html4/strict.dtd">
    XHTML 1.0 Strict:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    XHTML 1.1 DTD:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

    Take noteThis first step is about creating well-formed documents and producing a clean markup, but it is not a requirement for this branching method to work. You can "downgrade" the DTD or even put MSIE 6 into quirks mode if you want (or need) to.
  2. Mark up your document with semantic in mind (you should read these entries too: when semantic markup goes bad and SimpleQuiz). Make sure it includes all the necessary structural elements and hooks (IDs, classes, etc.).
  3. Run your file through the validator. Do not move to step #4 until it validates.
  4. Congratulations! Now your file is ready for prime time.
    In the markup, below the title element, write the following:
    <style type="text/css" media="screen, projection">
    @import "/css/basic.css";
    </style>
    
    About the media types:
    • screen is to make sure we do not serve the style sheet to all UAs out there.
    • projection will cause Opera to use the sheet in full screen mode.
  5. If you don't know about the box model already, it is a good time to read the beginning of this article. If you're already aware of the issue, remember to style accordingly (do not mix border and/or padding declarations with dimensions on the same axis).
    Now open "basic.css" in your favorite editor and create the rules that will style your document the way you want. Go through the whole process only using the browser you think is the best when it comes to web standards.
  6. Before going any further, you must accept that it is perfectly OK for a web page to not look exactly the same in every browser.
    Now open your document in MSIE 6. How does it look? If it looks fine and appears to function properly, then skip to step #9.
  7. To fix MSIE 6 issues, you create a new CSS file (msie6.css) that you import using a Conditional Comment, like this:
    <!--[if IE 6]>
    <style type="text/css" media="screen">
    @import "/css/msie6.css";
    </style>
    <![endif]-->
    
  8. You open "msie6.css" and you use the "usual suspects" to take care of layout and behavior issues:
    height:0
    To give layout to an element.
    display:inline
    To prevent MSIE to double a margin value on float.
    cursor:hand
    To force a change of the cursor's shape if needed. Note that such declaration is safe here, but would make the regular style sheet fail validation.
    #whatever {overflow-x:hidden}
    When italic text "pushes the envelop".
    Etc.
  9. Now we move to MSIE 5/Win (if you don't know how to run IE 5 versions along with IE 6, then read this great article by Manfred Staudinger). If you have styled your elements following my advice in step #5, you should not have too many problems related to box model. But in any case, Conditional Comments are there to help you out again. This time we use the following:
    <!--[if IE 5]>
    <style type="text/css" media="screen">
    @import "/css/ie5win.css";
    </style>
    <![endif]-->
    
  10. Same thing again, you use "ie5win.css" to fix what needs to be fixed.
  11. At this point, you can check your document in any other IE versions you want, using extra Conditional Comments to target any specific vector version. On the other hand, depending on the fixes needed to cater various IE builts, it is possible to implement Conditional Comments in a different way. For example <!--[if lte IE 6]> opens the door to IE versions 5 and 6 ("lte" stands for less-than or equal).

    Take noteWhen using Conditional Comments, do not forget to take into consideration that a new version (7) of MSIE is coming soon. For example conditional expressions like [if IE] or [if gt IE 5](greater-than IE 5) would not be safe.
  12. Now let's move to MSIE 5/Mac.
    To take care of this one, we need to use the IE5/Mac Band Pass Filter. This is the only CSS hack you should ever need to use. To import a styles sheet that only IE 5/Mac will parse, we place this filter right below "basic.css":
    <style type="text/css" media="screen, projection">
    @import "/css/basic.css";
    /*\*//*/
    @import "/css/ie5mac.css";
    /**/
    </style>
    
  13. You know the drill by now. Open "ie5mac.css" in your favorite editor and fix what needs to be fixed. To help you address specific IE 5/Mac bugs you may read this article or visit Mac Edition.
  14. What's left? Browsers older than version 5.
    If you've followed all the previous steps, your document should appear unstyled in these dinosaurs. In my opinion, NN 4 is the last one alive, the last one we should worry about. It is true that because of its poor CSS support, we cannot expect much, but still we can give it some styles to chew on. This time, to import the sheet, we use a Javascript solution:
    <script type="text/javascript" src="/js/styles.js"></script>
    This JS file contains the following statement:
    if (!document.getElementById) document.write('<link rel="stylesheet" type="text/css" href="/css/versions4.css">');

    Browsers that do not support getElementById (versions 4-) will parse "versions4.css" while others ignore the sheet altogether. Note that using Javascript is not an issue here, mostly because NN 4 cannot apply styles sheets without JS support.

    Take note If you decide to not include this script into your document, you must read about FOUC. Because you may experience FOUC if there is no link element or script element inside your document's head element.
  15. We are finished forking. Now we can add a print styles sheet to our document:
    <style type="text/css" media="print">
    @import "/css/print.css";
    </style>
    
    The above syntax fails with IE 5 Win (IE 5 loads the sheet). To be safe, it is better to use "link", as below:
    
    <link rel="stylesheet" type="text/css" href="/css/print.css" media="print">
    
  16. And since we are on a roll, why not including a sheet for small handheld devices (typically small screen, limited bandwidth)?:
    <style type="text/css" media="handheld">
    @import "/css/handheld.css";
    </style>
    
    If your print styles sheet and handled styles sheet are identical, then give both values to the media attribute in step #15 (media="print, handheld") and do not add the above block.
  17. Run your document through the validator again. This time check both (X)HTML and CSS.

You're done!
Your markup should look like this:

<style type="text/css" media="screen, projection">
@import "/css/basic.css";
/*\*//*/
@import "/css/ie5mac.css";
/**/
</style>
<!--[if IE 6]>
<style type="text/css" media="screen">
@import "/css/msie6.css";
</style>
<![endif]-->
<!--[if IE 5]>
<style type="text/css" media="screen">
@import "/css/ie5win.css";
</style>
<![endif]-->
<link rel="stylesheet" type="text/css" href="/css/print.css" media="print">
<style type="text/css" media="handheld">
@import "/css/handheld.css";
</style>
<script type="text/javascript" src="/js/styles.js"></script>

Take note Dreamweaver users may download this Snippet (version 1.1 - 2kb) that will write all of the above for them.

Take note Make sure "basic.css" comes before other sheets served to the same media type. The script can go anywhere within the head element.

Take noteNote that there are more media types than the ones I'm using here. The complete list of media types in HTML4 is:

  • aural,
  • braille,
  • handheld,
  • print,
  • projection,
  • screen,
  • tty,
  • tv.

CSS2 defines the same list with the addition of embossed to differentiate between braille tactile feedback devices and braille printers. Also, all is used to indicate that the style sheet applies to all media types.

But what about Safari, Opera, Camino, Konqueror, etc.?

Our styles sheets are designed for:

  1. "good" browsers with solid CSS support.
  2. "bad" browsers with weak CSS support, but a decent market share.
  3. "old" browsers with poor CSS support used by people stuck with out-of-date OSes or machines.

My take on this is that if a UA doesn't fit in one of these three categories, then there should be no need to worry about it.

For further reading visit the following URIs: