Stefan Hayden

Shift + Ctrl + Alt + S

CSS Caching Hack

If you change the HTML and the CSS of a page there is a decent chance that a user will get the new HTML but not the new CSS. This is especially true for sites with high usage and users that come back to the site several times a day.

If they only get the new HTML but not the new CSS then the site will break, the user will get confused, and you will look unprofessional. On the development site of this the problem is already solved. Having a Dev server as a place to test code is standard practice but how does this translate to CSS?

The problem is that the CSS is cashing on the client side and there isn’t an obvious way of telling the browser to un-cache it. Luckily the key word is obvious. Though it’s not in wide use there is a quick hack that will keep your CSS as fresh as your HTML.

The trick is to pass a variable on the end of the CSS file like so:

<link rel="stylesheet" xhref="http://www.stefanhayden.com/style.css?version=1" type="text/css" />

What does ?version=1 mean? This is what a URL looks like if it’s passing a GET variable from one page to the next. To the browser it means the page is dynamic and it needs to get a new version because code may have changed. The browser has no way of knowing if the CSS file is actually dynamic or not.The trick is to change the number each time you update the CSS file to make sure the browser always downloads the new code.

When a browser looks to see if it has anything cashed it compares file names. If you have “style.css” in your cashe then it’s not going to download it again. But if the browser compares “style.css?version=1″ to what the new HTML is “style.css?version=2″ then the browser thinks they are different files and needs to download the new CSS file.

The other reason this works is because you can add anything you want after the ? and the web page just ignores it unless it’s an actually variable on the page.

This seems to be a really good solution to version css and yet so few seem to use it. The only 2 sites I know of who do is Odeo and Sconex. Yet clearly we are in the middle of a big web boom with CSS being used every where. How are other people versioning their CSS so it doesn’t break the user experience?

In general I can’t see to many other solutions. You could make the CSS file parsed by the web server and pass headers with different cacheing info. I have not tried this but I’ll bet the browser would still cache the file as it does not know it is dynamic even if it is. You could rename the CSS file with .php but clearly no one is doing that and I’ll bet there is a browser out there that would not apply the styles because of that.

No every one gets to work on a large production site but with so many jumping in the area and quickly updating the service I’m surprised this subject has not been covered.

odeo, sconex, css, versioning, hack

122 Comments
Gravatar

Very cool. Thanks for that tip.

Gravatar

And what are the conditions when a user will get the new HTML but not the new CSS?

Gravatar

Interesting. I have applied your advices and I got the expected results. Congratulations

Gravatar

Your browser caches some stuff and not other stuff. Part of what it does and doesn’t cache is based on how recently you have updated the HTML.

The most common case is with a dynamic PHP page. These pages are meant to change and so the browser either tends not to cache them or doesn’t know it’s the same file with all the new GET statements on the end of the URL at each use.

Even though the PHP page is dynamic and is downloaded every time things like CSS and images on the page (like the logo) are NOT downloaded every time. In a perfect world the browser checks to see if any linked documents and images have changed. It is painfully obvious that this does not happen.

Browsers don’t download a new CSS file every time and it doesn’t always check to see if it even needs to download a new one

This problem is more obvious when working with large production sites where no matter when you update the CSS some one will be online. Hard refreshes (Ctrl + F5) always fix the problem but it only takes one bad page load to look unprofessional.

Gravatar

Hi Stefan,
I think that the technique I’m using is similar to yours, but will appreciate a lot your feedback.
I simply add a counter (#) to the end of the css name file every time i update it instead of add the PHP sintax ?version=#.
E.g. style.css => style1.css => etc.
Regards

Gravatar

Wow, how obvious was that? I used to do something similar for images way back in the day and never thought of doing this for stylesheets. Good call Stefan.

Gravatar

Mauricio:
That’s not a bad fix either. It’s something we used to do. My only argument against it is that you need to edit the CSS file and the link to the CSS file.

My way you only need to edit the link to the CSS file.

Both ways are perfectly valid. Thanks Mauricio!

Gravatar

you can do this with javascript files too… so when you update your ajax/page layout, you won’t have issues with old javascript running on a new DOM layout.

Jesse

Gravatar

Good point Jesse. I have yet to see that issue crop up with our javascript but I fully belive that any linked file has a chance of not being updated.

Versioning files this way is pretty easy and seems to be fail safe.

Gravatar

What’s “xhref” attribute? Just a typo?

Gravatar

I would say that Mauricio’s method is slightly better. Why? Because with the browser assuming it’s dynamic and downloading everytime, it’s using a lot of bandwidth. One of the advantages to external stylesheets is that it’s cached, so it speeds site performance and saves you bandwidth. I’d much rather rename the file and the link to have the updated CSS cached.

The only circumstance I see your method being better is if the changes are constantly occuring.

That of course is only valid if I’m right in assuming a browser always downloads a page when GET variables are passed in the URL (which your original write-up seems to agree with).

Gravatar

I personally don’t see the difference between using a counter as Mauricio suggested and using a querystring. Stephan’s argument against Mauricio’s solution is not valid, since in _both_ cases the link to the file must be modified in the HTML source. The only thing saved here is a rename of the actual css file, but if you’re modifying the HTML source anyway and uploading a new css file, it really doesn’t matter! Just my thoughts :)

Gravatar

If you are making the page dynamically, you could have the # in the article be the date of the css file on the server. That way it automatically gets updated and when the browser caches correctly, there is no extra downloading. This would be useful when many pages use the same style sheet over the site.

Gravatar

Will this work with .js files too?

Gravatar

It seems like a cool idea but it isn’t very practical. You might as well just send some headers to force the browser to download the new data.

Gravatar

讓CSS能夠正常更新的hack…

部分瀏覽器在更新CSS時並不會即時更新,需要用到Ctrl+R或Ctrl+F5的祕招..
原因出在於瀏覽器會對CSS做cache動作,對一般網頁設計者來說可能是很頭大的問題
CSS Caching Hack這邊提到:
只要將原始….

Gravatar

Well this is the nicest way to not to let browser cache the CSS, and fetch the CSS at runtime. But I guess this process is a bit time consuming as compared to the browser caching the CSS when the page is requested at the first time.

Gravatar

This method does not make the browser download the the file EVERYTIME. Why? Because now the browser is comparing style.css?version=1 to style.css?version=1 and thinking it’s the same file.

Weird? Maybe a little but I think it makes more sense once you see how large sites themselves cache a large portion of their dynamic pages for faster response time.

Trust me we would not use this method if it suddenly upped our bandwidth.

Gravatar

I’m using some similar technique on my site, but with the difference that my css file is server side and its different for the different pages. I mead: one css file , but with different content for different page.

Gravatar

[...] CSS Caching Hack – Stefan tells about a good way to make sure that browsers are pulling the most up-to-date stylesheet for a given webpage, and not the cached version [...]

Gravatar

How about @import – will that work the same way?

Gravatar

I can provide the developer’s point of view as to why changing the file name isn’t a preferred solution — it’s slightly annoying to have to rename a file in a version control system every time you change the CSS.

And in response to the headers comment — I’m not aware of a way to use headers to be able to push changes at an arbitrary time. You can tell a page to never cache, or to expire at a certain time, but this will either waste bandwidth or constrain you to release changes at predetermined times.

Gravatar

There is a Last-Modified parameter for HTTP Headers. We have not tested it but it might work… who knows.

Gravatar

We use a slightly different approach whereby we link one “super” CSS file in the HTML page that includes all other CSS files. The super CSS file has a cache validity of one hour (supplied via HTTP header instructions) while all included CSS files have a cache validity of one month. If a change is made to one of the CSS files its filename is changed to force the new version. We only need to change the filename in the super CSS file without having to change the HTML page. This way we can have good caching and avoid changes to the HTML page.

We have taken the same approach with our javascript. Have a look at the source of http://www.rabobank.nl/

Gravatar

[...] In a post titled CSS Caching Hacks Stefen Hayden explains how you can force the browser to load the latest CSS file and not the one cached by the browser. This has happened to me many times, especially when I’m working on a new layout and refreshing the browser after consecutive changes. Sometimes the latest CSS file just refuses to load. Posted in HTML | | del.icio.us this post [...]

Gravatar

We also do it with our flash swf’s because it has the same problems. I’m not sure, but i bet we got the idea from dunstan orchard or dan cederholm who did a lot of odeo’s initial design and css work.

Gravatar

CSS Caching Hack…

If you change the HTML and the CSS of a page there is a decent chance that a user will get the new HTML but not the new CSS. This is especially true for sites with high usage and users that come back to the site several times a day.
If they only get th…

Gravatar

[...] CSS Caching Hack (tags: css cache) [...]

Gravatar

[...] CSS Caching Hack. Умение браузерами кэшировать CSS-файлы считается одним из основных достоинств этой технологии, но иногда возникает потребность избежать этого. Например, при смене дизайна сайта. Конечно, ничто не мешает просто переименовать этот файл, но есть способ и поизящнее: достаточно просто приписать GET-запрос к его вызову. Получиться должно что-то типа этого: <link rel=”stylesheet” xhref=”http://www.stefanhayden.com/style.css?version=1″ type=”text/css” />. If you change the HTML and the CSS of a page there is a decent chance that a user will get the new HTML but not the new CSS. This is especially true for sites with high usage and users that come back to the site several times a day. [...]

Gravatar

I’m baffled that this post is generating so many comments. The technique of making URIs dynamic by adding fake GET variables, is conceivably older than i am.

Whats next? Revelations that you can customise your CSS layout by call server-side scripts, instead of *.css files from your tag? ooOOoooh!!

Gravatar

Great article,
but this hack doesnt defently run with all actuell browsers.

Ü.

Gravatar

[...] Hacking • Useful • Blogging • Tool • Web Design | Add To Del.icio.us | Digg ThisTrack with co.mments | RelatedStuff [...]

Gravatar

Cool. It seems like this should work for javascript also – another frequent victim of browser caching.

Gravatar

CSS Caching Hack…

Stefan Hayden discusses a simple ‘hack’ how to force the browser to download the latest CSS resource instead of using the cached version…

Gravatar

[...] New(?) CSS caching tip. I’m going to have to try this out the next time I make changes to a live site. [...]

Gravatar

Dave: This hack maybe as old as the internet itself but with no documentation and almost no site using it who is suposed to know about it?

Übertakten: What broswer doesn’t this work in? As far as I can tell IE is the wose offender of caching the CSS while Firefox doesn’t seem to have the problem of caching too oftain. Even still firefox just ignore the extra code.

Gravatar

I never tought about that. Might be usefull. Nive thinking.

Gravatar

Thx so much!

Gravatar

Dave, have you ever heard of HTTP-Headers? Like Last-Modified, E-Tag and Cache-Control? If you use this headers right, you never need such a »hack«.

Gravatar

Oops. I ment Stefan, not Dave.

Gravatar

[...] If you’re updating CSS to a website that’s already live, consider this technique. [...]

Gravatar

uncle baba ask of you when you coming stefan

Gravatar

ML,

I agree that using HTTP header would be great. Working with my developers it seems that certain parts of the header like Last-Modified are not strictly followed and so don’t work as well as you’d hope.

Gravatar

[...] Stefan Hayden has found a fix for this, which he wrote around April (I guess I was a bit slow on this issue), so HURRAH, looks like there is a solution to accessing different versions of css files without the need of renaming the files!:D [...]

Gravatar

[...] stefanhayden.com shows a neat (and easy) way to make sure the client fetches new CSS with HTML update: just add a variable at the end of the CSS with each update. [...]

Gravatar

[...] stefanhayden.com shows a neat (and easy) way to make sure the client fetches new CSS with HTML update: just add a variable at the end of the CSS with each update. [...]

Gravatar

this is just what i was trying to figure out
thanks for your help its verry much apreciated

Gravatar

My site allows visitors to use a wizard to upload a logo and splash image(updating the background images in css lines). When the user clicks save (submit), the images are not refreshed on reload in the preview iframe. But, if the user clicks preview, javascript reloads the iframe src dynamically calling the previewed css files, the images are refreshed. Both are using this query string technique, and at times, both are calling exactly the same css files. Why would one work and the other not work? Any ideas?

Gravatar

Great topic by the way. I figured this out by myself because I use it with PHP files a lot, but this is the first actual post I’ve seen to date covering this issue.

Gravatar

Sorryy plesae :(
rWong cawtegoyr…

will bew careful

Gravatar

Very cool! I used this tip/hack, and it is very easy and effective.

Well done.

Gravatar

Hi
Im not sure to understand
If i change my css version
do i have to reload each html page with
the new name of the css

Gravatar

Brilliant idea

Gravatar

Thanks a bunch…I read 20 articles before finding yours and now my issue is resolved. Great job!

Gravatar

Hi, :-)
but how to get the variable of version, or version=1 is enough.
Thanks

Gravatar

Great tip. I hank such coding convention help in many different ways.

Gravatar

[...] shows a neat (and easy) way to make sure the client fetches new CSS with HTML update: just add a variable at the end of the CSS with each [...]

Gravatar

Thousands and the dazzlingly buy cytotec dead hand estivities.

Gravatar

Test message
Sorry me noob…

Gravatar

[...] shows a neat (and easy) way to make sure the client fetches new CSS with HTML update: just add a variable at the end of the CSS with each [...]

Gravatar

It is not out-of-date information? Because I have other data on this theme. http://video-online-go.ru/map.html

Gravatar

If you’re using php, you can make this real simple. Here’s an example from my work website which assigns the unix timestamp as the css variable.

<?php foreach($css AS $css_d) printf(“\n “, $css_d, filectime(“css/$css_d.css”));?>

Gravatar

Hi Stefan, great post. What do you think to take my project about CSS and JS optimization into consideration?
http://code.google.com/p/headscripts/
It´s easy and very useful for large web applications that requires a high level of customizations. Thanks!

Gravatar

Cool, with the most browsers runs it.

Gravatar

If you’re working with Joomla then you’ll know how bad caching is especially in the development stages. Joomla itself has a cache module that can add to the problem. To cut a long story short, after 2 days of trying to clear the cached CSS files, using different browsers, 3 different platforms. I even dug deep into my system to clear the cache to no avail.

I finally came across this Blog. first I tried adding a version number as stated above but it didn’t work, then I tried Mauricio’s method and I was back in business. It is an old trick that I used to do but since I enjoyed a long time without caching problems I needed the reminder.

Thank you Stefan, Mauricio, and the rest. This post helped me a lot.

Gravatar

[...] tip from Stefan Hayden on how to make sure users get the latest version of you stylesheets when you do [...]

Gravatar

Hi guys, thanks for the great idea. I use the PHP function and don’t have any problems.

function cssInclude($filename){
echo “\r\n”;
}

I use it like and it works perfect. Uses the timestamp of last-modified time from file, output is like style.css?ver=1239793386, if file is modified it is automatically updated. Hope someone will find it useful.

Gravatar

This trick saved my butt while working on a local WP installation. For some reason Safari wouldn’t let go of the old stylesheet even though I’d emptied the cache.

Gravatar

Hi all, thanks for your contribe.

I think i have the good alternative, because you do not need any manual changes

i just pass “t” param in my CSS file like :

<link rel=”stylesheet” type=”text/css” href=”/style/mystyle.css?t=>

Whenever you change the CSS file, its modification date will change, so the browser will reload the file.

Gravatar

arf, php tags not allowed in comments…
i just said use filemtime php function on target CSS file and pass returned value in “t” parameter

Gravatar

Thank you!!

Gravatar

The best information i have found exactly here. Keep going Thank you

Gravatar

The only problem with using headers is that they react differently depending on which browser and what version the user’s browser is. The trick listed at the start of this page is quick and painless. Thanks for sharing!

Gravatar

Thanks, have done similar for other types of content. Never occurred to me to use it on CSS. You just saved me on a production release with some bad CSS behaviors. Simply and straight forward.

Gravatar

[...] costretto a cercare un alternativa. Grazie a Google ho scoperto che Stephen Hayden ha proposto un trucchetto per ovviare il problema. Il trucco consiste  nell’aggiungere una variabile GET alla fine del [...]

Gravatar

xhref isnt valide. why not:

href=”style.css?version=xy” ???

Gravatar

Thanks for the tip. works well.

but one question: if you have to change the “style.css?version=X” value for all references, why not just rename the file as style.versionX.css?

Gravatar

@zero Well if you rename the file then you have the change the file name AND what it’s called in the HTML. So more work.

Nut you could rename the file if you wanted to. If your website is setup well there should only be 1 reference to the css file in some header.php file. Chamging the v= is just a very low effort way to get the no caching effect.

Gravatar

If you have access to PHP then use

style.css?<=filemtime(‘style.css’)>

If the above doesn’t come out properly then I said use:

filemtime(‘style.css’)

to get the modified time of the file, so when you update and re-upload it, it will have a different number on the end and will therefore force browsers to re-cache it.

No need for name changing or editing the html each time you want to make a change in the stylesheet/javascript includes

Gravatar

VIOLA !!!

We recently gone through the same problem & end up in renaming all css files.

After reading this article I think we should have one tag (sorry I am from java backgroud so giving solution in J2EE words)which renders tag having some postfix (may be release no.) to css and js files.

While doing build & release we can define release no. & rename all css and js files. This will not change css & js files on your source repository. :)

I am going to implement this in our project.

Gravatar

To summarize…
1. adding GET paramters does the job but browser tends to recache the file with dynamic parameters (especially IE) doesn’t matter if parameter changes or not…

2. Renaming file is too much hassle… especially with versioning in place

3. With Apache and .httpaccess you can add rule to reference file style.css even if you call style134.css from HTML

simply it will ignore number in the filename.
Example (depends on your setup):
RewriteRule style[0-9]*\.css style.css

of course you have to have some admin rights and be able to modify .htaccess…
I am sure this is possible in IIS as well

- Automatically changing filename number by filedatetime is not ideal either… coz it adds additional hit to the file on harddisk on every request, but it is comfortable and maybe worth the loss. Changing html each time css changes by hand is too risky.

4. HTTP cache headers… probably the most prefered way, but involves a bit of work to get it working…

At the end this work should be done by webserver(s) and should be done properly… which is not…

Use Fiddler to see effect of different scenarios :)

Gravatar

Jesus, I see there are lots of kids here developing hello world apps. Why not rename the file? Stupid question. Imagine doing that in a portal with dozens of webapps and hundreds of stylesheets under version control. Thanks to Stefan, his hack is the only practicable solution by now

Gravatar

This is absolutely the right way to handle this cross browser (I agree with others nothing this approach is not new, but apparently a lot of people missed the memo…).

A point to add is that it actually *increases* caching, in a desirable way.

By default, some browsers will aggressively cache a CSS file and refuse to update it even when the content changes, unless you perform a hack like this, while others will download and display the updated one (even if you didn’t refresh and are just hitting the site again).

With additional GET parameters on the URL browsers that do not otherwise cache CSS files start to do so aggressively, until the GET parameters change. This side effect is desirable as it reduces the amount of superfluous traffic.

However, I suggest NOT simply appending the current timestamp (as suggested by one commentator) as that will increase the amount of traffic by having all browsers to re-download all CSS files on every page hit.

A $version variable is a more sensible approach (and on your development environment you can make it seconds since UNIX epoch if you want).

Gravatar

We found when using this that IE holds client side caches much longer than desired. Changing GET vars in the URL string will not always bust client side caches. Our fix was to use PHP and rewrite rules to have the caches bust themselves based on the files mtime in the file system. The mtime rather than being appended as a GET var is passed a directory (css/13456134/file.css) which forces IE to think it’s a completely new file and bust the client side cache.

We’ve written a PHP function to handle this automatically and put a rewrite rule in place to handle the resulting changes.

More info can be found here.

http://chad.ill.ac

Gravatar

[...] shows a neat (and easy) way to make sure the client fetches new CSS with HTML update: just add a variable at the end of the CSS with each [...]

Gravatar

On PHP, one of these may work:

<link rel="stylesheet" type="text/css" href="style.css?”>

<link rel="stylesheet" type="text/css" href="style.css?”>

Gravatar

Ops, there’s a stupid filter taking out the php code lets try again:


<link rel="stylesheet" type="text/css" href="style.css?" media="screen">


<link rel="stylesheet" type="text/css" href="style.css?" media="screen">

Gravatar

Man, haw a tech blog may work properly if the code are wiped out from the comments???

Gravatar

This is really a great post for me as i didn’t think about it before. Thanks for sharing it and will be appreciated if you will post again these kind of stuffs in future also.

Gravatar

does anybody knows how to cache .css and .js files for a better speed-loading website?

Gravatar

Question: I updated my site. The old css file was base1.css. The new file is base2.css. I updated my html files to point to the new css file. I didn’t delete the old css file off the server. Two months later I’m still getting 7% as many hits on the old base1.css file. Is this from browsers caching the old html files, search engines, or something else?

Gravatar

Just wanted to say thanks so much for this tip… I’ve been redesigning my site and was going crazy because the CSS was getting cached … this completely fixed it

Gravatar

thanks for this useful information :)

Gravatar

A suggestion to make this automatic:
Use a little PHP and the filemtime() function to make the number after “?version=” change only when the file modification time changes.
Essentially, this Fixes the IE caching… you never have to change anything manually again.

Gravatar

very nicely written. Thanks a lot for sharing it

Gravatar

Hi,
I insert the date and time stamp after css path … and in this way every refresh is “new”

<link rel="stylesheet" type="text/css" href="style.css?” />

Gravatar

I see here not apear the parameter after “?” … (it is the date/time stamp) wrote in php …
tray it my forum … http://fhuba.ro/viewtopic.php?p=982#982

Gravatar

Good trick. You can even use it inside a , with the @import statement.

e.g.
printf(“@import \”%s/css/main.css?version=%d\”;\n”, BASE_URL, getCSSLastUpdate());

Where getCSSLastUpdate is:

function getCSSLastUpdate() {
if (defined(‘CSS_PATH’) && file_exists(CSS_PATH)) return filemtime(CSS_PATH);
return 0;
}

(add a CSS_PATH define to your env file so that it points to whatever CSS matters).

Gravatar

just realise you can simplify the code above by just going:

printf(“@import \”%s/css/main.css?version=%d\”;\n”, BASE_URL, filemtime(BASE_URL . ‘/css/main.css’));

Gravatar

I agree with William S. PHP is the way to go

Gravatar

great tips. keep it up

Gravatar

Is it just me or does internet explorer completely IGNORE css?

Gravatar

hell yeah this is great

Gravatar

I have seen many css files included with ?version=number, i always just wondered. Almost thought css gets some GET values :P Thanks for informations, now all doubts gone.

Gravatar

amazing….. thanks for tips

Gravatar

amazing….. thanks

Gravatar

great tips and nice information you have shared, i like it.

Gravatar

Excellent tip. and its not even a hack if you really think about it.

Gravatar

This is extremely helpful, You are an excessively professional blog writer. I have registered your feed and turn up for in search of even more of your great posting. Also, I’ve got shared your website within my social networks!

Gravatar

Why it is not used is because HTTP GET with a parm , i.e ?, is a non-cacheable item and so this works because it never get it from the cache which is not a good thing. If you do this you have to make sure the web server is marking the content as cacheable.

Gravatar

Hey nice tip…!
Thanks a ton ;)

Gravatar

Oh man – thanks for this!
Was tearing my hair out with IE9 seeming to cache the CSS no matter what I did.
Worked straight up just adding ?Ver=1 after the css file call :)

Gravatar

Very elegant. Incredibly simple yet completely effective. How did I not think of this?

Thank you!!

Gravatar

Really nice solution. Thank you very much!

Gravatar

I use a similar solution, but thank you for this its a lot simpler and pretty obvious. Not sure why more websites don’t use this?

Gravatar

[...] users weren’t getting updates to CSS and image files. CSS is rather easy to resolve using the well-known query string hack, but doing the same for images referenced from within the CSS files is a bit trickier. Luckily the [...]

Feed Icon Comment Feed

Post a Comment