Stefan Hayden

Alt + Ctrl + 0

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

54 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

Feed Icon Comment Feed

Post a Comment