Stop using poor performance CSS expressions – Use JavaScript instead
Since the CSS support in Internet Explorer, especially in versions prior to Internet Explorer 7, has been lagging quite substantially, clever web developers have started using CSS expressions to mimic CSS functionality. However, few realize how this affects performance.
Explaining CSS expressions
The basic idea with CSS expressions is that you will have calculation and dynamic values for properties in the CSS code, something that people have found very useful. A simple example can be implementing max-width
behavior in IE 6:
#container{
width: expression(document.body.clientWidth > 1100)? "1100px" : "auto";
/* For web browsers supporting it */
max-width: 1100px;
}
The code above evaluates the available width of the body
element, and if wide enough, adapts the element named container
so it stretches to a maximum width of 1100 pixels. If the area needed isn’t available, it scales down to what will fit within the context.
Basically, any way you can use one-line JavaScript code, it means a possibility to dynamically style something.
It uses JavaScript?
Yes, for those who don’t know: CSS expressions is purely based on JavaScript, and through the CSS implementation in Internet Explorer, it opens up the option to write scripts in the CSS code.
Sweet!
You’re probably thinking “Sweet!”, and immediately start planning everything you can fix with CSS expressions to touch up on your CSS code for Internet Explorer. Away with nasty hacks; enter clean, proper and cool solution.
Sweet?
I’m afraid, my friends, that it isn’t that sweet. To begin with, many web developers seem to completely underestimate that this requires JavaScript enabled in the web browser to function at all. And since you don’t want your layouts to be JavaScript dependent, you will have to provide a proper fallback which will work without JavaScript.
The other major reason is that CSS expressions are very resource intensive. The resulting value of an expression isn’t just calculated once, but consistently while you’re using the web page. Add moving the mouse pointer around to that, and it will trigger even more evaluation from the expression interpreter.
You’ve probably experienced some web pages being even more sluggish than expected in Internet Explorer, but haven’t known about the reason why. Look no further: usage (especially heavy such) of CSS expressions is most of the times the culprit you want to get rid of.
Why do people use CSS expressions?
I have complete understanding of people implementing CSS expressions to cover up for shortcomings in the CSS rendering engine in Internet Explorer. I also believe that since the syntax is very easy, web developers have (as always with easy code) adopted it without seriously analyzing any possible downsides to it.
Use “real” JavaScript instead of CSS expressions
You will never get around the dependency on JavaScript being enabled for having a layout which is dynamically calculated in the same manner. However, there’s a much better strategy to achieve the same behavior and result in Internet Explorer, but without the performance loss: JavaScript
And by JavaScript, I mean real, proper JavaScript code included in an external file, and instead tied to event handlers. This means that the behavior, and thus the calculation, will only take place when that event occurs. In between, there will be no performance affection due to CSS expressions desperately trying to find out what the annoying user (to CSS expressions, that is) is doing in the web browser window.
A JavaScript example
To get the same result as the above CSS expression code sample, you need this code (as a suggestion included in a file named maxWidthFixForIE6.js
):
window.onload = checkAvailableWidth;
window.onresize = checkAvailableWidth;
function checkAvailableWidth(){
var container = document.getElementById("container");
container.style.width = (document.body.clientWidth > 1100)? "1100px" : "auto";
}
Too much code for your taste? No more tasty one-liners? Well, do you want funky looking code (which every web developer for some reason think is obliged to belong in the CSS file/-s), or do you want code which is reliable and gives the best performance for your users? I know what my pick is, at least…
For Internet Explorer 6 only
One more thing to note here is that you only want this example code triggered in Internet Explorer 6. Not version 7, and definitely not for any web browser provided by another vendor. Some will now cry out:
Web browser detection? That’s foul play, object detection for the masses!
Well, object detection is a great thing, and without a doubt the most suitable approach testing for feature support. However, in cases like this, there’s no proper way to check for lack of CSS support.
Since you also don’t want the JavaScript file included for every user and web browser either, you should address this by only serving it to Internet Explorer 6. The best way I think this can be done is by using conditional comments to filter out the web browser you want:
<!--[if lt IE 7]>
<script type="text/javascript" src="/js/maxWidthFixForIE6.js"></script>
<![endif]-->
Use JavaScript, if needed
One time or another, we get handled a case where there’s no way to accomplish a certain layout optimally for Internet Explorer 6 without JavaScript. And you know what? That’s just fine, shit happens.
But first, make sure it degrades properly without JavaScript. Second, implement it with JavaScript code instead of CSS expressions, for best performance and reliability.
A clean and simple solution … I like it. The only downside being that I feel rather stupid for not having thought of this myself. 😉
Excellent article Robert. I have indeed noticed some sites being unconventionally slow and even emailed a few and asked what they had done. Considering I have quite a good broadband connection it seemed odd to wait up to half a minute or more for a text page with 3 or 4 optimised images to load. So that might have been the likely culprit.
I haven't used CSS expressions myself but mostly because I never felt good about them. Somewhere things need to be processed.
Thanks for sharing the javascript solution.
I don't use IE CSS expressions, but I always wondered what their downside, apart from relying on JavaScript, was. Thanks for clearing that up!
[…] After reading Roberts Talks post about this code, I would suggest still to use this code but use proper JavaScript and include it via a script […]
I personally use the code that you wrote above. So now I guess I do not have any more excuses and can now use the proper JavaScript 😀
both CSS and Javascript have their unique behaviors.when we doing more complex designing, hope both are needed
Excellent, I wonder why I didn't think of this before. My reasoning about javascript usage for max-width is that it seldom breaks pages. Sure, lines will be very long, but they are still readable. I'll use your script, not expressions, in the future. Thanks!
Robert, just ask the people to stop using invalid <abbr>CSS</abbr> 😉
<abbr>OT</abbr>: That's probably intended, but abbreviations without a <code>title</code> could benefit from having no border.
Personally, I do not believe expressions are simply evil. Expressions work, whether it is worth using them it on your site versus performance is up to you. I found some expressions to work very fast without affecting performance while some are really heavy. It's all about testing and evaluating.
Besides that, events such as <code>onload</code> can be tricky as well. If not used right, the onload triggers after the site is loaded causing an ugly flicker which can be very annoying.
To be clear: there is no perfect solution for every project when handling specific limitations in IE. I find that the best thing to do is to find different solutions and evaluate which one works best for that particular project. And that can include expressions.
Thanks everyone!
Jens,
Ah, well, invalid CSS is somethimes necessary to deal with certain things in IE 6. For instance, <code>zoom: 1;</code> is at times a better approach than <code>height: 1%;</code> to trigger <code>hasLayout</code> (especially in conjunction with <code>overflow: hidden</code>).
David,
Personally, I see no downsides to using JavaScript instead. I didn't think it was in the scope of this aricle to go into event handling, but I agree that <code>onload</code> is at times not the event you want to trigger something like this. No one wants the nasty flicker, right?
Therefore, I'd encourage everyone to use some sort DOMContentLoaded approach to apply these things. I've written one approach in ELO – Encapsulated Load Object and it is also part of my DOMAssistant library in the DOMAssistantLoad module.
I'd rather agree with "sometimes easier" since there often are alternative ways to trigger or avoid "hasLayout". However, I just wanted to tease 😉
Interesting,
The funny thing is that I read about the performance problems with CSS expressions just today while reading the tips from YSlow regarding better page performance. I also came to the conclusion that i should use javascript to do this instead. YSlow, which I by the way know about from your blog.
So thanks for the nice, unobtrusive javascript solution and also, thanks for the tip about YSlow.
Gabriel,
Funny coincidence! Anyway, I'm glad to hear that it helped!
That IE-expressions can put heavy load on scarce resources, is a well-known issue. Performance-testing should definitely be high on the list whenever they are used.
However, I haven't seen any good Javascript alternatives that can outperform the more complete (tailor-made) IE-expressions mainly used to "fix" IE6' lack of CSS support, and I'm not sure what a good Javascript alternative should look like if it should perform the same task(s).
The "in-sync" performance is mainly what I'm after, since I use IE-expressions to emulate regular CSS support. Do you care to elaborate on what Javascript alternatives we have that performs the same tasks with less use of resources?
Georg,
In-sync approach is a bit different, and I'd say fairly uncommon. But, at first thought, I don't see why JavaScript couldn't met the same demands with the proper events applied.
It gives you a more granular control, and hopefully just the possibility to have better performance by removing any constant but superfluos chance check.
Georg,
I see where you’re coming from, and it’s a pretty complex situation. But in that case, how about Dean Edward’s IE 7 script?
Robert,
thanks for the response.
Yes, most settle for what I call "lagging fixes", where well-written Javascript with the right set of conditions is superior to IE-expressions.
CSS is (supposed to be) handled pretty instant (in-sync) though, and that's why I ended up writing my own, conditional, IE-expressions since I wanted to emulate proper CSS-handling – making it appear as if IE6 supports the relevant CSS.
Besides, since we're dealing with an obsolete browser-version, I prefer to waste some of its resources instead of mine.
I'm not proficient enough in Javascript to write anything better at the moment, and what I've found across the web doesn't seem to work more seamless or light on resources. Always open for suggestions though.
Robert,
I went through and tested a few layout-solutions with Dean's script, a couple of years ago. I ended up neither pro nor con, but it seemed I had to tailor my CSS a bit for the IE7 script to make the most out of it.
I ended up not using Dean's work for anything but inspiration.
Georg,
Well, inspiration counts too! 🙂
Robert,
Sure inspiration counts. Besides: inspiration is so easy to turn into something completely different 😉
Thanks for the chat.
The idea of CSS expressions reminds me of Adding Style and Behavior to XML with a dash of Spice, an old submission to the W3C (1998).
Georg,
Thank you!
Christophe,
Ah, good connection. Thanks!
Hi Robert, Thanks for your post —
I'm trying to implement this, but, well, I have no idea where to put the code…! I'm a complete javascript newbie. Do I put this in the css? Do I make it it's own js file and then call it from my header? Sorry for being clueless, but I would greatly appreciate a quick nudge in the right direction.
Cheers —
Zack,
As suggested in the post:
I also recommend reading up on JavaScript best practices, for instance in Unobtrusive JavaScript, since it’s a vital tool in developing web interfaces.
[…] Nyman’s article about using JavaScript instead of CSS Expressions is a must […]
A follow up on the link to Spice: Daniel Glazman (invited expert to <acronym>CSS</acronym> <acronym title="working group">WG</acronym>) and David Hyatt (Apple) are working on a proposal for <acronym>CSS</acronym> Variables. (Discovered through Laurent Jouanneau's blog.)
Christophe,
Yes, we'll see what happens with that. 🙂
[…] http://www.robertnyman.com/2007/11/13/stop-using-poor-performance-css-expressions-use-javascript-ins… […]
[…] http://www.robertnyman.com/2007/11/13/stop-using-poor-performance-css-expressions-use-javascript-ins… […]
Hi,
This article is great. It help me with the expression problem. Thanks, Robert.
Best regards,
Inair
Surely any script execution at the Style Sheet stack of the browser is a performance issue and more importantly a security threat. No wonder it makes IE the most insecure browser on the market.
Good news is Microsoft is ending expressions in Internet Explorer as announced on Thursday earlier this week.
A very nice move towards the standard-compliant browser.
Inair,
Good!
flash tekkie,
Yes, I was very glad about that decision!
Nice one, another Yslow follower here… I'm a js novice but I think this might work as another way of including the code (instead of using [if lt…]), no IE6 to test on here…
<code>
function checkAvailableWidth(){
// min/max works better with slightly different values?
var container = document.getElementById("container");
container.style.width = (document.body.clientWidth 1012? "1010px" : "auto");
}
// window.attachEvent only followed by IE6? or IE7 as well?
if (window.attachEvent)
{
window.attachEvent('onload', checkAvailableWidth);
window.attachEvent('onresize', checkAvailableWidth);
}
</code>
I have a big block of sitewide js so my idea is to just stick it in there instead of having a separate file. Not sure how those calls work when there are other ones looking out for 'onload' as well.
waitangi,
The problem with using <code>attachEvent</code> is that it is present in IE 7 as well, + in Opera, who has tried to mimicked it.
Therefore, using conditional comments is the best way to achieve this, and also, personally I prefer a clean separation in my code between real code and other code used to cover up for certain web browser flaws.
Ah cool thanks for that info Robert, I've followed your advice and removed the ie-only code to a separate file inside conditional comments.
Almost at the holy grail of YSlow A! (just a few grand on CDN and it's there 🙂 ).
waitangi,
Great! 🙂
That CDN thing is a bit off, I think. It's really only valid for major web sites being accessed from all around the globe. Don't worry to much about it. 🙂
[…] maxWidthFixForIE6.js — Emuler la propriété max-width pour IE6 : […]
[…] found this article on the web, which says that reqular expressions are very expensive on the page, and you should use […]
Nice job. Works like a charm!
Zac,
Happy it helped! 🙂
[…] maxWidthFixForIE6.js — Emuler la propriété max-width pour IE6 : […]
Hi,
I tried to use the above code but it doesn't seem to work for me. Maybe I'm doing it wrong?
If you have IE6 you can check out the web address. It is giving me problems with both the left div and the right div.
My structure is something like this:
<code>
<html>
<head>
<style type="text/css">
#wrapper{ width:980px; margin:auto; background-color:#fff }
#header{ width:980px; position:relative }
#middle{
width: expression(document.body.clientWidth > 940)? "980px" : "auto";
/* For web browsers supporting it */
max-width: 980px;
padding:20px;
overflow:hidden;
clear:both;
}
#left{ float:left; width:200px }
#main{ width:auto; margin: 0px 0px 0px 210px }
#content{
width: expression(document.body.clientWidth > 480)? "480px" : "auto";
/* For web browsers supporting it */
max-width: 480px;
min-height: 400px;
margin: 0px 250px 0px 0px;
}
#right{ float:right; width:240px }
#footer{ clear:both; width:980px; margin:auto; padding:20px 0 }
</style>
</head>
<body>
< div id="wrapper">
< div id="header">
</div>
< div id="middle">
< div id="left">
</div>
< div id="main">
< div id="right">
</div>
< div id="content">
</div>
</div>
</div>
</div>
< div id="footer">
</div>
</body>
</html>
</code>
Nevermind I fixed the problem. I changed some of the code and set a conditional statement for IE6 to change the div#middle padding to 10px.
moleculezz,
Glad that it worked out for you!
How did you track performance on css expression vs javascript ?!
Olav,
I think the best resource on that is the statement from the Yahoo Performance Team on CSS expressions.
[…] Rightly so, Microsoft has dropped support for CSS expressions with IE 8. The better choice is to use proper event handlers. Here is a great article further exploring the problem with CSS expressions. […]
[…] maxWidthFixForIE6.js — Emuler la propriété max-width pour IE6. […]
[…] want to rely on a class name for that).Note that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] want to rely on a class name for that).Note that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] want to rely on a class name for that).Note that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in a small performance […]
[…] ????????CSS??????????min-width??????????????????????????? […]
[…] Stop using poor performance CSS expressions – Use JavaScript instead – Robert’s talk […]
[…] maxWidthFixForIE6.js – Emuler la propriété max-width pour IE6. […]
Something has apparently changed in the several years since this interesting article was written, and IMO its advice is no longer sound.
In IE9 (under Windows 7), expressions in CSS do still work, and max-width still does not work. Consequently, I routinely use the following workaround to get max-width functionality:
<!-- workaround for IE's lack of support for max-width -->
<!--[if lte IE 9]>
<style>
div.maxwidth {width:expression( document.body.clientWidth > 41 * 1.370 * parseInt(document.body.currentStyle.fontSize)? "41em":"auto" );}
</style>
<![endif]-->
</head>
<body>
<div class="maxwidth" style="max-width:41em;">
This is not dependent on Javascript, because it works even when scripting is disabled in IE9.
You can see an example on my web site: http://www.sealevel.info. Disable scripting in IE, and then watch what happens as you adjust the IE browser window width: perfect max-width emulation.
Note #1: the
<!--[if lte IE 9]>
is because I’m optimistically assuming that Microsoft will finally fixmax-width
in IE 10. I’m probably wrong. I can’t fathom why they didn’t do so in IE7, IE8, and IE9.Note #2: depending on your padding, margins, etc., you might need to adjust the 1.370 magic number slightly, to avoid a “width-glitch” when resizing the the IE browser window by dragging the border left & right.
Dave,
It’s a very old article, but max-width has been supported in Internet Explorer since version 7, so it should all work for you. Make sure you have a strict doctype to trigger standards mode.
[…] maxWidthFixForIE6.js – Emuler la propriété max-width pour IE6. […]
[…] Rightly so, Microsoft has dropped support for CSS expressions with IE 8. The better choice is to use proper event handlers. Here is a great article further exploring the problem with CSS expressions. […]
[…] that the CSS expressions we use here are not as bad as the ones generally used to mimic min-width and the like. These are only evaluated once, which should result in asmall performance […]
Expressions and other IE specific garble frustrates me… These types of practices complicate everything, I’m currently farming out several expressions peppered throughout several css documents and it is maddening. I am glad IE is catching up, but at the end of the day they still have quite a few nonstandard solution and the benefits of omitting them far out weight answering the ‘difficult’ questions posed by customers such as “why does this part of the page look slightly different in IE vs ‘insert any good browser name here’?” at any rate I’m a little raw about this whole topic at the moment and before I go any farther I’ll simple say what I wanted to on the topic… If you are working on a client site it is a complete disservice to resort to cross browser solutions using any Microsoft (or browser specific non-sense). If it is not standardized don’t do it… The owner of such a solution is going to eventually have to pay someone like me way to much to o thru and remove all the javascript from the css directives (in the case of expressions a that is)… Being a lazy developer doesn’t mean taking crappy design shortcuts, It means doing it right the first time…. If you have to implement cross browser solutions for css or javascript PLEASE do it correctly by doing some form of feature detection (Modernizr is great by the way). Take the time to do things correctly, everyone will benefit in the end.