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 403 guest comments so far.
My next project is PNG heavy with a liquid layout using max-width. This Very usefull article could'nt have come at a better time. Nice work :)
David, that is an amazing idea. Thanks!
Cool, but we really souldn't have to serve different style sheets like that. Doesn't it defy the whole point.
Thank you David! This is evo-, I mean, revolutionary.
Andrew - you're absolutely right we should not have to create different style sheets. But the sad fact is that too often we do have to give different rules to different browsers, if we want our web pages to look consistent. I think this is just a cleaner way of doing it.
Just one problem with lousy browsers like OPERA - it's user-agent string defaults to emulate IE. I've used this kind of solutions before, but don't anymore, just to cater to the sloppy browser called Opera, that wants to emulate a worse browser called IE.
hi,
its great but idea isn't new or revolutionary. in 2001 at www.denkwerk.de we have work so for nokia-europe and other projects ;) You can use it for javascript, too!
But it is good that you wrote this way, because it is better as hacks. Opera is a problem but other browser or proxy are will make problems too. At a proxy i can define other browser as i will use.
other way is that you can create php script in css.files. why this work? you can setup apache server that css.files will parsed as php-scripts. "add-handler" for php....
thank you for this small tutorial ;)
Toolpi
Some testing:
K-meleon, MS Win 2k, Custom User Agent selected - MS Internet Explorer.
"You are using Internet Explorer"
Opera 7.54 and 8.0 - no switch (Opera UA):
"You are using Opera
You are using Internet Explorer
You are using Firefox
You are using Mozilla
You are using Netscape
You are using Safari"
Opera 7.54 and 8.0 - switched to any other UA (IE or Mozilla):
"You are using Opera"
In my opinion it is still better to use known rendering engines' behaviors that are not emulated when UA is changed. If a rendering engine does (not) understand something, it is UA independent, so using CSS hacks we know what we get.
But it is a good article, and I think I'll give it a try in some project.
For you Apache users, add this line to your .htaccess file:
AddHandler application/x-httpd-php .css
Now, you can rename your "styles.php" to "styles.css"
Also, to keep your if () statements tidy and on one line, refer to the PHP manual's .
Yes, opera is a problem as well as other browsers that can switch user agents. We have to be alert of those rare cases. Yes, you can use the Apache line Chistopher described above (thanks!) to make .css files parse PHP code. Nice.
Regarding Alternative syntax, I prefer the casual by default.
Also, the example is pretty lousy because the sample file will print out all browser names if none was found or if the version is lower than 5... I hope you get the point anyway.
I think that the best way to tackle the problem, from a maintenance point of view, is to have the 'hacks' separated out into seperate versions... when I say hack I refer to browser specific 'fixes', rather than traditional css hacks.
So you'd detect the browser agent, serve a 'common.css' stylesheet with common code (easier to maintain) and then serve a 'fix.css' stylesheet with the browser specific fixes.
That way you only have to maintain one main file (common.css) and the fixes are easily separated and maintained.
Just a thought.
I wouldn't call this new at all, browser sniffing has been around for ever and is considered "very bad practice". All this technique is doing is changing it from a per stylesheet test to a per statement test.
The problems with IE shouldn't stop you writing good, server independent, managable, stylesheets. You'll have to put in a couple of hacks but that's much better than dynamically generating stylesheets based on the dodgy behaviour of current browsers. What if IE 7 fixes the problems you're having with its layout engine (and one would hope the hacks we've used to get around it), if you're using this code it will still be sent the broken version, which would most likely look like garbage in the new browser. I don't want to have to go back through every site I've done every time a new browser gets released. The way to be doing things is to be writing stylesheets to standards and then using hacks if you must to get them working on common browsers rather than the other w
Nice article! To Adam Burmister, yes that is what I do as well and in my humble opinion is very correct. I think that sending a common.css and a bad-browser.css is faster than generating the css on the fly using php. So only an if statement will determine whether you are going to send that extra css. Of course, in case of IE, there will be two requests to the server for the 2 css files, which possibily is slow, but... that's life for IE users anyway.
To Jake Badger, yes that's another point of view, but I think that it's better to serve valid but dynamic CSS, than broken and hacky CSS in a single file. And regarding IE7, trust me, when this happens we will all be there to update our sites!
Regards
It's not about how many files you have, you can link to two files (one clean, the other with just the hacks) and use a pass filter to link to them, the point is that you shouldn't be chosing what to display based on the user agent. Some browsers give other user agent strings (or can be set up to) and different versions of browsers will support different feature sets even though, at least with the test given above, they will report as the same.
With one stylesheet and some hacks (either in their own file or in the main file) we are moving towards the ultimate goal of one standard stylesheet that will work everywhere, doing sniffing like this is moving backwards.
I think this is the most practical & safe, albiet potentially the most time consuming approach to the problem at hand.
It sucks that we have to hack our CSS files to get browsers to support perfectly legal CSS rules.
What scares me the most every time I write a hack (which I find my self doing less and less these days the more I consider the following point) is that at some point something could change with major browsers that will make some hacked designs potentially blow up.
For example use selectors like "* html" to hide IE rules from Mozilla or "*>" to hide Mozilla rules from IE and either browser implements support for those selectors in future releases your design could go quite wrong. And if you don't keep vigil over every old site you develop you might not even know until you start receiving angry calls from your customers.
This approach protects you from anything like that ever happening and as browsers mature and increase their support of CSS, old styles wil
Dont mean to be rude, but when you say "font-end developer", you mean "front-end"? ;-)
To comment the article, I like the idea. I dont like the hacks either. Unfortunately I use TopStyle to design my stylesheets, and having server-side code in them will break the preview in TopStyle. :-/
Jake "What if IE 7 fixes the problems you're having with its layout engine, if you're using this code it will still be sent the broken version, which would most likely look like garbage in the new browser."
This is not true. The script allows you to specify rules for specific versions. So if you don't want the "fixes" to apply to future versions of IE, just make sure they are there for IE6 and lower.
I have thought of doing this very thing... but I just cant bring myself to start creating server side stylesheets... I often develop for different environments, be it Webobjects, PHP, JSP, or ASP. Can someone please explain to me why including selector hacks in your css are so non-semantic? My CSS still validates, even though it looks somewhat ugly with "Voice Family"'s everywhere. Sometimes I think the validator fervour for developers is less about a respect for semantic design, and more about bragging rights among peers.
David: This is just a way of moving the problem to the server-side.
I don´t see why this is better than an ugly CSS hack. I might even be worse if you want to move your web to another platform... We want one style for all browsers! :-)
You can switch user agents in Opera, but I guest you have never take in look to its user agent. There is always an Opera written at the end of the string. So it is pretty easy to find if it is Opera.
Secondly, I don't like this method. I agree that in the moment it is a pain to create a layout which lookes the same on all browsers. But if you start to use this method to serv different styles, there wont be a need for web standards.
there is a cache problem with this method the css will not being cached by the navigator, in a huge css it can be a real problem.
It's a goot solution but make all the property that need the hack all together in a different css
Good point goetsu. Try adding these headers at the top of your php file along with the content type:
header('Cache-control: must-revalidate');header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 7200) . ' GMT');The CSS will be cached for 2 hours, which should be enough.
Of course the best way is to have one style for all browsers, but unfortunately that is not how the real world works. Browser sniffing is nothing new and I must also add that it is not 100% reliable either, but I think it is a very interesting alternative to those ugly hacks.
This is not the definitive solution, just an alternative, but it's a good alternative.
Regarding hacks, I'm more fond to place IE hacks to separate files and use conditional comments, because it does not interfere with other browsers and control over the user-agent versions is pretty acurate. You can live without the fear that the next version will somehow go around the hack. It's simply because conditional comments are not a hack for IE — it's perfectly legible for that particular browser.
I found David's example useful mostly with Opera, which often behaves strange, but supports all those 'advanced' selectors. I also wrote an article explaining Opera detection with PHP at http://www.maratz.com/blog/archives/2005/04/20/dropdown-menu-with-fix-for-opera/ There's also a table with predefined user agent strings.
To Jake Badger, what you said is correct, but I trully believe that anyone playing with the user agent string of his browser will definately get himself into many broken webpages.
Regarding CSS caching, what I do is generate my actual CSS files using php on the fly, just before the
Sometimes I will also add another level of complexity, by detecting really old browsers. There was a guy once who visited a site of mine with Netscape 6.2.x (not very old i guess) and the whole navigation system of my site would not work. What was causing the error was a CSS div centering technique that was not supported well by ancient browsers. So I solved my problem by serving another CSS for them
Mathias Bynens had a similar idea a while ago: http://mathibus.com/archive/2004/10/phpss
I was a bit surprised to see something like this written. This is essentially just browser detection but moved server-side and something that many advocate staying away from. Yes, hacks are ugly but I'd prefer them over creating an entirely new stylesheet to work on just for another browser. Before I got the job I currently hold, they did that excessively and it made updating anything a pain because I had to change it in 6 different places. If you take care with writing your CSS and designing your pages, few hacks are really needed and I don't think it's necessary to create a new file for them.
Hacks are essentially work-arounds taking advantages of bugs in a system. They're not pretty, but this is the same thing at the basic level: a work-around but slightly "cleaner." This also appears to require quite a lot more coding and effort to do what a simple hack could accomplish.
I suppose it's a matter of preference so I'll stick with the few hacks I need.
Of course it's a matter of preference. But if you are like me - a hopeless perfectionist - you soon realize those small browser differences. Text size is larger in opera 6 for mac, mozilla has it's own rule for outline, IE/mac has an annoying float bug etc, etc. A browser detection script in the CSS file could come in handy instead of using hacks, not only because their useage can be very limited but also to deliver a much cleaner code to the end user.
I can understand IE hacks to a point, but something like what was outlined in this article kinda defeats the purpose of standards.
Standards, imho, should be used to advance browser technology and capability, not cater to old-n-busted browsers that people simply shouldn't be using anymore.
In a perfect world, everyone with any browser should be able to view and use your site...but sadly, it's anything BUT a perfect world. It's time to accept the fact that not everyone can use every website, no matter how many hacks or workarounds are employed. There will always be someone who has an issue.
Standards is the line in the sand...let the user decide if they wish to cross it. They can continue using NN4.7 or they can get hooked up with Firefox. But I think the effort required to allow every browser ever made to be able to use a website is a waste of good pixel pushin' time.
I would like to see this done with javascript
Where is the part where this is less ugly than CSS hacks?
"Standards is the line in the sand...let the user decide if they wish to cross it. They can continue using NN4.7 or they can get hooked up with Firefox."
Since when did standards become a user-end issue? And how would you explain to your client that some customers can't browse the site properly because they are not in the web standards club? Real world clients don't care about browsers, they care about customers. And your job as a developer must be to give them the best possible experience, no matter what browser they use.
Wilson: .
You're kidding, right? I can't believe what I'm reading here - it's like we're encouraging use of the CENTER tag all over again, and coding in HTML4.
Though I have to commend solid PHP code (which could be optimized a little further, but overall is excellent) I think this kinda defeats the purpose. People will be spending almost double the time that they'd usually spend writing PHP rather than CSS.
Not to mention that Wilson is entirely right - in my entire career of development, I can count on one hand the number of people that asked "Does it work in something other than IE" - educating clients aside, I'm not going to bill someone for time writing a css/php hybrid when I could just hack my way around it.
And finally, just to recap - serving static content is almost always faster (as per my last benchmarks anyways) than serving dynamic content. Unless we took into account gzip or come other kind of compression, I simply don't see the point.
But then again, what
"I'm not going to bill someone for time writing a css/php hybrid when I could just hack my way around it." - Ryan, would you bill someone for all the time it took you to find out about all hacks availible for all browsers? Once you've got the detection script up and running, the rest is a piece of cake (if/else).
I'm glad we have a healthy discussion going on about CSS hacks and the alternatives available. You cannot hide the fact that a hack is basically faux markup, created to force some browsers to ignore it because they can't parse code that isn't allowed.
Excellent Idea!
Why didn't I think of that?
*cough* *cough* *cough*
hmm... seem like my link got swallowed even though it worked in the preview: http://richardathome.no-ip.com/index.php?article_id=106
I think it's just like old JavaScript browser detection.
Though it's a solution for this problem, I rather write a css code withou hacks doing my best for the user have similar experiences, though not identic, than write this php code.
I hope one day every browser speaks the same language, so we won't need all this stuffs.
kinda smooth, but very much missing the whole point of standards I would say, and entangling server side coding too, I thought we were trying for some abstraction of elements.
Thanks for theis great article. Could not agree more with you ideas.
I also hate using bug based hacks to make a thing work.
To me, the important point behind semantics and standards is that we should understand each other when we speak. This has two levels :
First, we need to speak the same language.
Second, we need to interpret the language in a similar way.
To fix the fact that browsers don't interpret the language in a similar way, people have started fiddling with the language by applying CSS hacks, putting emphasis on the fact that browsers do not quite speak the same language.
For some reason, some people think this is more standard compliant, because they give the same file to all browsers. But with the use of CSS hacks, they are not giving the same CSS to all browsers. How is that different than two different files ?
We should start by using the same language for all browsers - no hacks! - and then cater for the fact that they don't all interpret it in the same way. That means giving browsers different sentences, using techniques such as browser snif
The idea works. It's also not a great idea, as always, you shouldn't test browser strings, you shoud test support of standards. CSS hacks work on any browser that understands them. Testing user-agents just means headaches later in the day when you need to keep adjusting the PHP to detect new strings or when a browser's support improves and your script is still pumping old CSS to it, or when a new browser altogether comes out...
User-agent sniffing is not the answer, as any JavaScript developer will tell you.
Oh, while I'm here - the email field's character restrictions are too low, and it's rejecting my valid email address.
Wouldn't it be simpler to serve
mysite-firefox.css to firefox
mysite-iewin5.css to iewin5
and so on?
Just wondering.
Urgh. No, no, no, no, no!
You know what this leads to?
<? if ($browser == "IE") { ?>
/* IE specific css here */
<? } elseif ($browser == "Firefox") { ?>
/* Firefox specific css here */
<? } ?>
/* No one seriously uses other browsers anyway, right? Oh well, tough to be them, I can't be bothered to write any generic css. */
You do it yourself in your final example:
$v >= 5
There's absolutely nothing that guarantees that future browsers won't start from version 1 again. Yet they'll sure as hell be able to do CSS.
We went down this path already - back in the 90s. Hell, ancient parts of my own site do exactly this!
The entire idea behind css hacks is that they somewhat approach testing for actual capabilities. It's not as good as javascript's:
if (document.getElementById) {
but at least it's somewhat close, and in most situations you can write the css hacks forward compatible. That is, valid css that all capable and _future_ browsers will handle correctly, but specific buggy browsers will not.
* html more selectors { IE specific stuff; }
/**//*/ Mac IE specific rules; /* */
No future browser will mess that up, because there isn't a parent element for html, and because does not escape the closing of the comment. It's surgically targetting old and known buggy browsers - and user_agent faking will not mess things up.
Finally, what's with this silly 1000 char limit?
and what happened to my backslashes?
The last part of the comment should be:
/*\\*//*/ Mac IE specific rules; /* */
No future browser will mess that up, because there isn't a parent element for html, and because \\ does not escape the closing of the comment. It's surgically targetting old and known buggy browsers - and user_agent faking will not mess things up.
"And how would you explain to your client that some customers can't browse the site properly because they are not in the web standards club?"
Isn't that precisely the point of standards? That users CAN access the site no matter what platform they're using? If we do our jobs properly, then everyone should be able to use a given website. Not everyone will have the same user experience, but the site IS accessible.
If a client insists that every browser be able to see the site the same way, then you're obviously not using standards to build the site.
I think most of the comments make one thing clear: This is not the golden solution for everything, it is serving David's and other people's preferences.
If you don't like hacks visible in your code, it's one way to do it. If you work in projects where everything besides IE can be neglected, there you go, just set up one valid css. If you don't like mixing the client and the server side, don't use it.
Actually, I can't really warm up to it as I have a whole browser-basket to cater for in my projects, and I prefer the css hacks, as they (for now) catch every rendering engine they need to catch. But there's no guarantee that the next generation of IE or Firefox doesn't fall for some of the hacks, but not others, and you have to change your stylesheets all over again.
In the end I agree with da dawg in saying that, ideally, you get a design (or create one) that can be built without hacks and without breaking in your set of browsers. In real life, deal with the different browse
plagiats beat me to it -- why make a huge mess of your css file, when you can simply serve up browser-specific css files?
Don't get me wrong -- not one file for each browser, but an additional file that overrides the CSS classes that would normally require hacks (or the techniques above).
I've described it here:
http://o2b.net/archives/no-more-css-hacks/
oh how long ive been waiting for something like this! thanks for this great article; looks like i need to freshen up on my PHP skills now.
While the technique is objectively feasible, solid, and even worth some peoples' while, I must disagree with the analogy to XHTML cleansliness.
I'm currently trying to develop a "style" guide of some ilk for my uni's student-based webteam... pulling a line from it.
"CSS is for presentation only, if you have to use various non-validating tricks-of-the-trade to get things to work then so be it – it’s not like there is a validating engine for information architecture and looks anyway."
If you're not using a table-based layout hopefully you'll be marking up your layouts semantically. If that's the case then why are legalities being attributed to the aesthetic and principled design aspect of the layout, i.e. the CSS? Personally, so long as your hacking is clean i.e. not grotesque in the "I'm hacking every other line for every browser on the planet" kind of way, I feel that "hacks" are alright.
Anyone feel that I'm fairly "wrong"? Enlighten me. ^^
If you install browscap.ini correctly, all of the code at the top of this article is completely unnecessary. Use PHP's get_browser() function instead. The code is compiled in, making it much faster than a user-defined function. Not only that, it's also more thorough. See:
http://www.php.net/manual/en/function.get-browser.php
for more details. ~d
This isn't really wise - I left behind this solution some two years ago - it was the first to come to my mind when I need to send different stylesheets to IE and Gecko.
CSS filters (if used wisely) are browser-capabilities-dependent, however this is user-agent-string-dependent -- globally browser sniffing is not good for this solution.
RIGHT ON to: J Badger, Maratz, D Dawg, R Brooks!
Reasons AGAINST php processing
1) Server processing time
2) Browser Sniffing doesn't move forward for new browser without recoding
3) PLUS abscrations is killed as the production level. Many css coders are designers, not programmers. Don't make them have to understand logical structure to implement design. Don't.
Reasons FOR css hacks
1) Once you find the right hack (they are MANY resources) you can repeatedly without effort. Lines of syntax for css hacks are far less than the php logical structure quivilant. If you wanna use php code forking, use it to send an additional static style sheet to that browser type, and let cascading and STANDARDS do what you need.
2) Most of the css "hacks" used ARE NOT HACKS! Example, html>body is thought of a "hack", when really its a css2 standard for a contextual first level child element. IE doesn't undersand it? Fine. The right values will cascade over in compliant browsers.
R U
I really don't see what's bad with conditional comments - they are valid and easy. Of course you can distinguish only MSIE vs. all the others, but that's usually all you need.
Many of the comments seem to imply that with the browser sniffing based solution, you will need to recode for future browsers, but not with the CSS-bugs based solution.
Now I don't get this ; this is not about browser sniffing, this is about HOW you use it. I can code my standard CSS, which will be common to all browsers. Then use browser sniffing to FIX KNOW BUGS in OLDER BROWSERS. Now, how is that not future proof ? What is it I will have to recode ?
The CSS-bugs based solution is no more future proof than the browser sniffing one. If a new version fixes the CSS-bug you rely on, but not the problem you were fixing, then you too will have to recode.
"The CSS-bugs based solution is no more future proof than the browser sniffing one. If a new version fixes the CSS-bug you rely on, but not the problem you were fixing, then you too will have to recode."
You are not relying on "css-bugs" but rather VALID css selectors. If a new browser then uderstands those selectors it will most likely implement CSS correctly. If not then write code that will attach a new IE7 only style sheet, for example, and let it cascade over the other values. Don't code fork at the selector level.
Also, the mack hack /* /* is valid CSS, it's a comment. Given that MS stopped developing MAC IE 2 years ago, I don't think I new version will fix their bug and implement css the same.
In the case of the box model hack, the short cut version is not valid--margin-- but the full hack is still valid CSS. U can us this for IE5 only, as we have seen IE6 HAS fixed thier bug AND their box model.
VALID sytnaxes fix 99% of the rendering problems.
Although the article is about CSS Hacks, I see great benefit in using the same basic method to reduce maintanence of the css files in another manner.
I have a basic 3 colum layout that I use over and over. The problem is that each different site I design uses different graphics which all have different sizes (obviously). So I have to go into the css and tweak the margins, padding and content values to fit the graphics with each new site. I think I could let php determine the size of the graphic and echo out the rule sets.
Though I personally don't have a 'css hacks' itch to scratch, your article will be a major help to me and save me a lot of time. Thank you!
t.
I have an idea to make this tool simpler.
Because most of "hacks" are requred for IE5.x, and some of them for IE6, we could use the sniffer to import another stylesheet:
if ($o == "WIN" && $b == "IE" && $v < 6) echo '@import "ie5x.css";';
and keep IE5.x styles in separate document.
I know there are conditional comments for this purpose, but there may be some situations where all you can change is the stylesheet (no possibility to add conditional comment to the html code).
In the first paragraph, I think you mean "break" instead of "brake."
why havenot you developers of this site used different style sheets? my opera shows your work not in a proper way. it looks pretty bad
I'm totally with Sander - this reminds me of browser sniffing javascript from the 90's. Where does this method leave other capable browsers - Omniweb, Shiira etc? Are they left out?
I've found that my hacks (such as they are) only need to be for IE 5-6, so the methods that Sander mentioned are all I need. Even conditional comments get this done neater, and keep all the IE specific stuff in a separate file, away from all the CSS for those browsers that get it right.
I agree that hacks are ugly but i think that this is a somewhat wrong approach, firstly browsers are being updated and therefore problems within these browsers are updated.. i believe it's better that we try and make browsers work with CSS, i.e. make microsoft wakeup..
I agree that hacks are ugly but i think that this is a somewhat wrong approach, firstly browsers are being updated and therefore problems within these browsers are updated.. i believe it's better that we try and make browsers work with CSS, i.e. make microsoft wakeup..
I am already using PHP replacements in my style sheet to dynamically change styling based on user preference (VERY USEFUL for making user interfaces accessible i.e. session contains users preferred font size, color scheme etc.) But have encountered a couple of problem:
1. The stylesheet is never cached by the browser so has to be reloaded every page.
2. If the dynamic stylesheet has a lot of replacements/logic, the browser (mainly IE) presents the page WITHOUT styling initially then adds the styling. This makes a page layout jump.
I have tried to force the caching of the PHP/CSS to no avail.
As an aside, pawel's comment is about the best way to perform conditional CSS switching in my opinion but it annoys me no end to use a conditional to include styles, plus the overhead of writing a bunch of stylesheets to do the same thing....... So, the hacks at the moment seem to be the most effective method :(
this is a good idea but the major setback with this approach is that your CSS won't be cached. having headers that control caching won't do much so i what i do is something like this (under PHP):
$ua_map = array( 'ie' => 'ie.css', 'nn' => 'nn.css' );
$ua = 'my useragent'; // assign detected browser here
?>
you'll just have to come up with several sheets with slightly modified versions. not that hard i think.
*points to the above*
Yes, it's the 90s all over again.
Browser sniffing is one of the reasons to use css hacks, not vice versa. Rather have one stylesheet that caters for all, than a sniffer script that will need constant updating every time a new browser arrives on the market. The web is littered with broken and just plain wrong detection scripts.
Furthermore, the more we serve different content to different browsers, the less motivation there will be for developers to confirm to universal standards.
This sucks, why? Because "user agent" string is newer trustworthy thing.
A positive list of User Agents? Ouch! That's exactly the kind of advice that'll make thousands of websites unusable for any browser you are not explicitely including in your list. As many said before, the 90s all over again.
Btw.: since when is »@import« a hack?
This is a really, really interesting article, but I agree with other commentators who have already pointed out that this approach is
i) dangerous in view of the difficulty (impossibility?) of reliable browser detection in the face of the ever-changing landscape of 'compatibility-faked' user agent strings, and for this reason this approis not future-proof, and that
ii) using php to generate static content _destroys cacheability_, one of the main benefits of CSS. This really harms useability and increases costs. To be quite clear about this, users who hit FORWARD then BACK will pay for this, and users of 28.8k modems or smartphones might wonder what's 'wrong' with the site.
Restoring cache-friendliness can be done, but it requires a _lot_ of work (I've been there :-) - so this article should be regarded as very much incomplete so long as it lacks the essential donkey-work php logic to send cache control headers, handle conditional GETs and NOT MODIFIEDs and so on, and so o
I generally build sites to the Firefox/IE6/Safari Benchmark, and then use Tantek's filters to pull the various IE flavours into line. I think this is a much more desirable approach than heaving all that PHP code around ;)
http://www.tantek.com/CSS/Examples/
The problem is that this method is far from fool-proof. Since browser detection is built upon the user agent string (which is easy to spoof/change, and some browsers report false UAs), it is highly unreliable.
I too, believe that using CSS hacks is setting us up for failure in the future as the parsing bugs the hacks rely on are not guarenteed to be fixed along with the rendering problems we're using them to fix. We might end up breaking our own code.
I would say that for IE-related problems (which are the majority of rendering issues), Conditional Comments is the way to go. They might not have originated with W3, but they are a way to deliver content to IE5.x+ that is built on a feature that will probably have longevity (unlike CSS hacks). For more see my writeup at DigitalGoof (http://www.digitalgoof.com) on Conditional Comments. For lasting usability, I think they make the most sense.
-Nate
So what if CSS hacks are "ugly"? I'm over it. I'm ignoring that portion (75%) of your cause.
Nobody ever looks at CSS source. When money's on the line, we have to face the fact that CSS Hot or Not score is irrelevant as long as it works. Not to mention, your solution requires programmer knowledge of PHP and Apache, which may not even exist on my next web host! Enough said...
Love the site, though.
I think browser detection is a really bad idea simply because it's so unreliable.
I typically identify myself as MSIE6, Win when running Safari or Camino to access some sites (and then forget to change it back when leaving that site).
Personally, I skip hacks and detects alltogether. The site might not look perfect in defect browsers but as long as people can read it, I'm happy.
Of course, I don't design commercially.
Viewing the demo with Mozilla 1.7.7 shows just why this shouldn't be used; It said:
You are using Opera
You are using Internet Explorer
You are using Firefox
You are using Mozilla
You are using Netscape
You are using Safari
In other words, I think you're using an inefficient method of filtering.
This is an old idea dismissed by leading web designers due to the load put on web servers and the problems with detecting browsers that are stealthed for security or where people use websites that relay information such as http://anonymouse.ws/ which will end up giving unexpected results.
Tantek Çelik once said, "Design for humans first, machines second." These hacks are purely so that visitors do not have to put up with constant errors in design and since it works well to have these hacks and there is really no side-effect of adding these hacks, I believe they are a just cause in web design.
Very interesting article,
With let you I translate a large extent this nice article to Persian language in my blog:
part1: http://weblog.alvanweb.com/2005/07/17/php-css-hacks/
part2: http://weblog.alvanweb.com/2005/07/15/css-hacks-preface/
why use heaps of lines of string functions when a regexp will do?
$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);
OR
preg_match("/(".$parent.")/([0-9,.]+)/", strtoupper($_SERVER['HTTP_USER_AGENT']), $browser_info);
Before anybody bleats about performance, benchmarks show it's 10% quicker to use the regexp.
the box model hack you mentioned in the article will validate if you add another backslash like:
.content
{
width: 700px;
padding: 0 100px;
voice-family: ""}"";
voice-family: inherit;
width: 500px;
}
Of cause you can use any server side language like ASP or .net to produce the same results. ASP uses VB Script many of you may have already used Visual Basic for your school projects and it’s the same sort of thing.
Oh dear guys I have just realised what your doing is absolutely pointless! You need to give a separate style sheet server side NOT produce a server side CSS file. This is because the point of having an external style sheet is that it is cached on the client side. Server side pages are not Cached and have to be generated on every page view.
To solve the problem above you can mod-rewrite the URL to end in .CSS. However on larger sites this is still not ideal because it requires programmers time because the code may need compiling if its anything more than PHP and Classic ASP.
Hi,
One more comment. I'm someone who is brand new to web development. It's taking me a lot of time to figure out exactly which hack I need so that IE will do one thing, but Netscape will not, etc. For example, even though I understand the basics of the child/parent hack, it is still taking me a lot of time to correctly put it into practice. For this reason, I like this article. I come from a programming background, and being able to specify the browser I'm trying to isolate with php is a lot easier and less time-consuming to me than trying to get the syntax of the hack exactly right.
I have written a similar argument against CSS Hacks here:
http://www.aspiramedia.com/fadtastic/?p=29
I hope I'm allowed to post this link. It is relevant.
I've applied the same general thinking to a recent client's website. But instead of using PHP to avoid hacks, I've used it to detect a users browser and then display a certain stylesheet depending on which browser they use. In my opinion it's much easier and less code intensive than the method you've outlined here.
good article nonetheless.
Avoid hacks because things have been farther complicated with half fixes in IE7. If you need IE7 in quirks mode then I believe you have to use at the top of your X/HTML
I like to use css 2.0 selector tags, like the ones below:
body {
width: 760px;
font-family: verdana;
font-size: 10px;
margin: 0 auto 0 auto;
}
html>body {
width: 760px;
font-family: verdana;
font-size: 10px;
margin: 0 auto 0 auto;
}
IE will recognize the first body, but not the second - however Mozilla or Gecko based browsers will recognize the second and not the first.
It works beautifully and keeps with the standards we're all after.
All the people complaining about the fact that this method is not or will not be compatible with other / new browsers are missing two important points.
1. The very same can be said for hacks (or should we call them "work-arounds" for those people splitting hairs and saying some of them aren't hacks?). It is very well possible for example that IE7 will fix the child selector bug used to write code specifically -not- for IE, but not all the bugs that said code worked around. All css pages using "work-arounds" will have to be recoded in that case.
2. With php you can do the following:
if ($browser == "IE" && $version == "5.5")
{
// code for IE 5.5
}
else
{
// code for all other browsers
}
That said, the php code in this article isn't very good or clean which led to people seeing all browsers detected with certain UA strings. That could be easily fixed.
Personally I prefer the comment method though since most workarounds are only for IE anyway.
I see a lot of people arguing that this sort of server-side css "hacking" takes more time to code than normal css hacks. In my experience, it is quite the opposite.
For my projects, I have written a bbcode style markup for my style sheets that is parsed by php. Only 1 line of php at the beginning and two at the end. The markup I use looks like this:
[? internet explorer 6]
// CSS
[else]
// other CSS
[end]
Where the question mark means "if" and I can alternatively use < (less than), > (greater than), ! (not). Specifying the version is optional.
Anyways. The point behind this is that you don't necessarily have to compromise speed or legibility of your css when using server-side "hacks".
Thank you! This saved my day! :D
There is a css hack that works for all versions of internet explorer, including ie7. You can read about it here:
http://www.ibloomstudios.com/article7/
Nice article. Tho I haven't got the time to read all comments, I will surely check back tonight :)
The 90s all over again. I love it.
My response, which details browscap.ini, is here (it's too long for comments here).
beyond the arguments against sniffing etc...
honestly, I don't see why writing more server side code is better than a hacked CSS... actually it may be worse as it munges up more of your presentation code with styling. this takes the CSS out of a designers hands and puts it back in the developers.
as a developer who was primiarily a designer originally, I want to delegate my work to more hands...
as a designer I wouldn't want to look at the crazy moon language.
interesting idea, but not my cup of tea at all.
please for the love of all that is w3c, if you are reading this page, please don't use this technique.
the .css files are normally cached by proxies, for better performance. If we use .php files, would it still be cached?
Other than that, your idea is excellent.
Thanks...
This comment is directed to suresh solomon. You will note that at the top of the article, the is what ties the style.php to the sometitle.htm. The is what makes the browser cache the stylesheet (). What's more, only the code that pertains to the UserAgent (browser, IE5.5, Mozilla5.0) will be cached. In other words, if you are viewing the page in Firefox 1.5.0.4, which uses Mozilla 5.0, all the coding for the versions of IE (5, 5.5, 6, you get the picture) AND all the coding for previous versions of firefox, AND anything else that doesn't use the Mozilla 5.0 code 'scheme' will not exist in your cached style.php.
This comment is directed to chad, and all who feel the same.
One of the main advantages to server side scripting, aside from the fact that it helps streamline code for faster processing is that it allows the use of variables in a non-variable conforming language (HTML, CSS,..). The above is just one example of the way to code your pages. Another altogether different way is to manipulate the code so that you only have to do it once, every time a new browser/version comes out. Take the box model hack: if you create the code as a set of variables that are read from the code itself, then all you have to do is create an equation that always modifies the final code. Eg. (standard css of div id="main" in Mozilla): #main {width: Apx; height: Bpx; margin: Kpx Lpx Mpx Npx; padding: Wpx Xpx Ypx Zpx;}
Create the equation (for IE5.5): {width: (A-L-N-X-Z)px; height: (B-K-N-W-Z)px; margin: Kpx Lpx...} You get the deal. Once you make the code once, you can default it on all future php/cs
I'm having an issue with a site I'm building trying out this technique... it's a total work in progress, but Firefox is not parsing the CSS at all (this would be the latest version of Firefox on both Mac and PC) whereas it's working beautifully for all other browsers I tested (IE Mac & PC, Safari, Opera etc.) What could be causing the problem? Any help would be appreciated.
I'm having an issue with a site I'm building trying out this technique... it's a total work in progress, but Firefox is not parsing the CSS at all (this would be the latest version of Firefox on both Mac and PC) whereas it's working beautifully for all other browsers I tested (IE Mac & PC, Safari, Opera etc.) What could be causing the problem? Any help would be appreciated.
Mostly you only need to differ between IE and non-IE. In this way, using php in css is quite better then using non-standard, unreadable Hacks!
Hiding filter Attribute in Mozilla-Browsers did not work with Star-HTML Hack therefore the php way is in this solution the better one.
thanks for links..
mirc turkce mirc
mirc
hikaye
thanks.
thanks for all.
thanks :)
thank you. wonderful web page.
thanks
thanks.
mirc indir
thank you
To allow browser caching insert this code at the top of the php file.
<?php
$headers = apache_request_headers();
// If there is a 'If-Modified-Since' in the request header and this file has NOT been modified since the 'If-Modified-Since'
if (isset($headers['If-Modified-Since']) && strtotime($headers['If-Modified-Since']) >= filemtime(__FILE__))
{
header('HTTP/1.1 304 Not Modified');
die();
}
// Set the cache to expire in a week
$nextWeek = gmdate('D, d M Y H:i:s', mktime(date('H'), date('i'), date('s'), date('m'), date('d') + 7, date('Y')));
header('Expires: ' . $nextWeek . ' GMT');
// Set when the file was last modified
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime(__FILE__)) . ' GMT');
// Do browser tests and output here or if you want to save cpu too you can do this,
// but make sure to check the modified time of 'actual_css.php'
include('actual_css.php');
?>
There's also this method, i
Sorry about that, it got cut off for some reason.
There's also this method, it uses javascript:
http://rafael.adm.br/css_browser_selector/
thanks
There is a css hack that works for all versions of internet explorer, including ie7. You can read about it here:
Interesting article.Thanx for the deeper look inside css!
Since when did standards become a user-end issue? And how would you explain to your client that some customers can't browse the site properly because they are not in the web standards club? Real world clients don't care about browsers, they care about customers. And your job as a developer must be to give them the best possible experience, no matter what browser they use.
thanks. wonderful
Interesting article.Thans
And how would you explain to your client that some customers can't browse the site properly because they are not in the web standards club?"
Isn't that precisely the point of standards? That users CAN access the site no matter what platform they're using? If we do our jobs properly, then everyone should be able to use a given website. Not everyone will have the same user experience, but the site IS accessible.
tnnkss...
tnnkss...
thanks
thanks
thanks
Thanks for the articel- Greetings from Frankfurt
thx for the great information very useful … keep up your nice work
thanks..
thank you very good idea
thanks for links..
thank can
thankss
There is a css hack that works for all versions of internet explorer, including ie7. You can read about it here:
thanks for all
thankss
thank you
thanks
thank you very nice article
Since even so did standards become a user-end issue? And how would you explain to your client that sundry customers can't look over the site nicely being they are not in the web standards bunch up? Real Einsteinian universe clients don't bitter draught about look throughrs, they agentship about customers. And your job as a fixer imposed be to give superego the best possible experience, no being what window-shopr they use.
this is great stuff on CSS and at the end of the day, the browsers will always prevent the designers from delivering consistent-appearing websites. no matter what we do....We come with solutions now then IE8 and the next versions of other browsers are released and we are back to the drawing board.....
Hiding filter Attribute in Mozilla-Browsers did not work with Star-HTML Hack therefore the php way is in this solution the better one.
Thanks a lot.
Great tutorial, i find it very helpful. Thanks for it.
Very useful information. Thanks !
Thanks
Thanks
vidrom.com
While the the particulars is objectively feasible, close, and by turns worth certain peoples' while, I moth and rust mismate snowball the analogy to XHTML brightensliness.
I'm currently trying to accrue a "strictness" guide of brilliant ilk for my uni's student-based webteam... pulling a line from it.
"CSS is for presentation only, if you have to use inconsistent non-validating tricks-of-the-trade to get materiel to octofoil then so be it – it’s not of a piece there is a validating propjet for information composition and looks anyway."
If you're not using a table-based charting predictably you'll be insignia up your cuts semantically. If that's the case then why are legalities being attributed to the aesthetic and principled artifice face of the array, i.e. the CSS? Personally, so long as your hacking is dexterous i.e. not grotesque in the "I'm hacking every other line for every browser on the Earth" kind of way, I appreciativeness for that "hacks" are not half
thanks for links..
Since when did standards become a user-end issue? And how would you explain to your client that some customers can't browse the site properly because they are not in the web standards club? Real world clients don't care about browsers, they care about customers. And your job as a developer must be to give them the best possible experience, no matter what browser they use.
thanks for post great share
thanks man
thanks