Skip to Content


Articles / No More CSS Hacks

No More CSS Hacks

Associated links:

Introduction

If you are a web designer or front-end developer, you are probably familiar with how different browsers or user agents displays your code in their own way. Picture this: You are pushing pixels and refining your designs so it fits perfect in your Firefox browser, but when presenting your design to the client in Internet Explorer, your pages might brake completely. Bye bye contract. Designing with CSS is no exception. On the contrary – table based layout seems to be more cross-browser consistent than CSS positioning. This probably one of the reasons why several big names still uses tables in their web design layouts.

CSS Hacks

To compensate these browser glitches, many CSS designers have been working on setting up CSS hacks. A CSS hack is a way to force some user agents to ignore a certain CSS property by putting faux code into the CSS file. One of the most infamous issues when designing with CSS is the Box model. IE5/Windows and IE5.5/Windows misinterpret the CSS1 box model by placing border and padding inside the specified width instead of outside. Here is an example of one of the most common CSS hacks used to solve this:

.content
    {
    width: 700px;
    padding: 0 100px;
    voice-family: "\"}"";
    voice-family: inherit;
    width: 500px;
    }

So what does this mean? The first rule width: 700px; will apply to all user agents. But there is a second style rule, which takes advantage of a CSS parsing bug in IE5/Windows and IE5.5/Windows, to apply a width which is then overriden. So IE5/Windows and IE5.5/Windows will read width: 700px and all other browsers will read width: 500px. So far so good. Except that everyone will see your hack.

Why Hacks are Ugly

There is something fundamentally wrong with how hacks work. They are based on producing errors in the CSS code to exploit browser flaws that prevents them from parsing certain CSS properties and values. Most CSS hacks works fine enough, but looks really bad and a hack like the one above does not validate using the W3C validator. If you are interested in semantics and standards you would never put a similar hack in an XHTML file, so why would you do it in the CSS file?

The Other Way

What if we could detect browsers and serve different CSS rules to different user agents, without using hacks or conditional comments? What if the end user or validator never saw the CSS rules specified for other browsers than the one they are using? We can. Many server side languages can detect browsers just as good as any CSS hack, and in this example we will use some simple PHP magic to make things happen.

Let's Get Going

To be able to use PHP in a CSS file, we need to link up the php file in the XHTML header as CSS and then send the correct header in the php file. As we don't need the @import hack anymore, put this line in the header of your XHTML file:

<link rel="stylesheet" href="styles.php" type="text/css" />

Create a new file called "styles.php" and save it into the same directory as your XHTML file. The first line in this file will be a header command to define a text/CSS header to the document. Once this is done, we can start producing variables in PHP and use them to print different rules in the CSS file depending on user agent. Let's create a small application that detects browser types and versions and platform, and then put these values in variables for later use:

<?php
header
("Content-type: text/css");
$d = detect();
$b = $d['browser'];
$v = $d['version'];
$o = $d['os'];
function
detect()
    {
    
$browser = array ("IE","OPERA","MOZILLA","NETSCAPE","FIREFOX","SAFARI");
    
$os = array ("WIN","MAC");
    
$info['browser'] = "OTHER";
    
$info['os'] = "OTHER";
    foreach (
$browser as $parent)
        {
        
$s = strpos(strtoupper($_SERVER['HTTP_USER_AGENT']), $parent);
        
$f = $s + strlen($parent);
        
$version = substr($_SERVER['HTTP_USER_AGENT'], $f, 5);
        
$version = preg_replace('/[^0-9,.]/','',$version);
        if (
$s)
            {
            
$info['browser'] = $parent;
            
$info['version'] = $version;
            }
        }
    foreach (
$os as $val)
        {
        if (
eregi($val,strtoupper($_SERVER['HTTP_USER_AGENT']))) $info['os'] = $val;
        }
    return
$info;
    }

Let's use these variables to print out user agent specific values, taking the box-model hack as an example. We will use simple if/else statements to check our variables, but you could also use ternary operators. What we are doing here is basically: if platform is windows and browser is IE and version is less than 6, width is 700px, else width is 500px.

.content
    {
    padding: 0 100px;
    width: <?php
    
if ($o == "WIN" && $b == "IE" && $v < 6) echo "700px;"
    
else echo "500px;";
    ?>
    }

There are no limits to how useful a script like this can be for the advanced CSS designer. In the rule above, IE5/win and IE5.5/win will see width: 700px; and all other browsers will see width: 500px;. Without hacks and invalid CSS markup You can even skip the popular @import hack to prevent browser versions below 5 to display the CSS. Another useful example would be to serve .gif instead of .png to IE5/win & IE5.5/win if you are using alpha transparency as background:

body
    {
    background: url(<?php
    
if ($o == "WIN" && $b == "IE" && $v < 6) echo "background.gif";
    else echo
"background.png";
    
?>);
    }

Here is another scenario: You want to apply max-width, but just found out that IE doesn't support it. So you found out about a max-width hack, but don't like to put ugly javascript expressions in your CSS. Here's how to serve the javascript to IE only:

body
    {
    <?php
    
if ($b == "IE") echo "width:expression(document.body.clientWidth > 800? \"800px\": \"auto\" );";
    else echo
"max-width: 800px;";
    
?>
    }

Final Example

The sample PHP/CSS file in this example will hide certain selectors and only show the selector that contains the correct browser information. At the same time we will get rid of the @import hack and serve no CSS to user agents that doesn't support it properly. You can watch what the html file looks like at our Demo page. Don't forget that you can download all associated files to this article here.

<?php
header
("Content-type: text/css");
$d = detect();
$b = $d['browser'];
$v = $d['version'];
$o = $d['os'];
function
detect()
    {
    
$browser = array ("IE","OPERA","MOZILLA","NETSCAPE","FIREFOX","SAFARI");
    
$os = array ("WIN","MAC","LINUX");
    
$info['browser'] = "OTHER";
    
$info['os'] = "OTHER";
    foreach (
$browser as $parent)
        {
        
$s = strpos(strtoupper($_SERVER['HTTP_USER_AGENT']), $parent);
        
$f = $s + strlen($parent);
        
$version = substr($_SERVER['HTTP_USER_AGENT'], $f, 5);
        
$version = preg_replace('/[^0-9,.]/','',$version);
        if (
$s)
            {
            
$info['browser'] = $parent;
            
$info['version'] = $version;
            }
        }
    foreach (
$os as $val)
        {
        if (
eregi($val,strtoupper($_SERVER['HTTP_USER_AGENT']))) $info['os'] = $val;
        }
    return
$info;
    }
?>

<?php if ($b != "OTHER" && $o != "OTHER" && $v >= 5) { ?>

/* BEGIN CSS RENDERING */

body
    {
    background: #fff;
    font: small/140% verdana, sans-serif;
    padding: 4em;
    margin: 0;
    }

<?php
echo ($b =="OPERA") ? null : ".opera { display: none; }\n";
echo (
$b =="IE") ? null : ".ie { display: none; }\n";
echo (
$b =="FIREFOX") ? null : ".firefox { display: none; }\n";
echo (
$b =="MOZILLA") ? null : ".mozilla { display: none; }\n";
echo (
$b =="NETSCAPE") ? null : ".netscape { display: none; }\n";
echo (
$b =="SAFARI") ? null : ".safari { display: none; }\n";
?>

/* END CSS RENDERING */

<?php } ?>

This article was written by David Hellsing

David Hellsing is a designer and web developer living in Gothenburg, Sweden. He is the founder and gentle dictator of Stylegala and the swedish design firm monc.

Are you a web publisher?

We are always looking for people who can write good articles about web design, css and standards. Are you one of them? Talk to us.

There are 8 guest comments so far.

commentat 20:57 on 15 August 2008, kozmetik wrote:

thank you

commentat 08:01 on 16 August 2008, Roy wrote:

Wow. All this time I've been using imports and hacks and error.css just to get around the IE bugs and you come up with this brilliant work around.

I will definitely start using your method from now on.

Thanks for the great write-up!

commentat 15:00 on 16 August 2008, Pascale wrote:

It's very interesting

commentat 09:12 on 17 August 2008, chat wrote:

thanks

commentat 10:24 on 17 August 2008, chat wrote:

thanks

commentat 21:15 on 17 August 2008, Robert wrote:

Odd... just yesterday I was annoyed at how IE 6/7 handled padding so I said to hell with it and wrote something almost exactly the same!

But this will be replacing that!

Thank You

commentat 10:44 on 19 August 2008, sexe wrote:

very good work ! interesting

commentat 13:24 on 21 August 2008, Werbeagentur Graz wrote:

Hi David,

Thanks for this code.

Add a comment:

(required, non-public)

  |  Chars left: 1000

Keep the comment relevant and constructive.
A valid email address or URL to your site must be provided, or the comment might get deleted. Content seemed inappropriate or offensive may be edited and/or deleted. Avoid explicit language. Email addresses are never displayed. Line breaks and paragraphs are automatically converted - no need to use <p> or <br/>. Quotes & apostrophes are automatically converted to smart punctuation. Be careful when copying and pasting portions of entries or other comments. The following inline HTML elements may be used: <strong><em><pre><q><blockquote><code>. All other code will get removed before posting. Don't forget to close your tags.


All articles

Search

Features

Stylegala BookStore
The Stylegala BookStore has a massive archive of great books for you as a professional..
Bullet madness
Bullet madness is a list of 200 bullets, arrows and icons uploaded by our users.
CSS Reference
An alphabetical list over the most common CSS1 and CSS2 syntax and properties.

Sponsors

Logo design for $149

Advertise here