I’m sure just about every web developer is familiar with client-side stylesheet caching. You know how it goes, you’re making changes to a stylesheet and checking them in your browser and then, all of a sudden, the updates you made don’t show up. When this happens, you either click refresh like a spastic monkey or clear your browser cache and the world returns to normal.
Much more frustrating than that experience is server-side stylesheet caching. Although I’ve seen this happen periodically on Linux servers as well, our Windows testing server here in the office is a cache maniac. If you refresh a page on the server a few times, the machine will start serving a cached version of the stylesheet…and continue doing so for several minutes. You can clear your browser cache and refresh a zillion times, but you’ll still get the cached version. When you point your browser directly to the CSS file, it will actually show the latest version, but when you go back to the page you were trying to refresh, or any page that links to that stylesheet, you’ll still get the cached version. It’s enough to drive me mad, especially when I’m already working on fixing quirky IE issues.
While the server caching settings really should be reconfigured, the accepted local method of dealing with this annoyance is to add a query string to the stylesheet url like so:
<link rel="stylesheet" type="text/css" media="screen" href="css/screen.css?foo"/>
This essentially fools the server into thinking the file must have server-side code, hence forcing it to re-load the stylesheet.
While this parlor trick stops the server-side caching, we often work on sites that do not have the stylesheet seperated into an include, so you can add the
?foo to the stylesheet href value on one page, and as soon as you jump to another page, you get the old stylesheet again. Additionally, we often forget in our final cleanup to remove the query strings when we’re done working on a site, leaving behind our query-stringed stylesheet links for the world to see. Bah!
What’s the solution? Ideally, adjusting the server’s cache settings. As a stopgap though, or for situations where I don’t have control over the server’s cache settings, I wrote a bookmarklet that reloads all the linked stylesheets with a query string of the current timestamp attached. I used a timestamp rather than the usual
?foo because sometimes it seems like the server caches the
?foo query string and we end up using
?foo1, ?foo2, ?foo3… This way, the query string is guaranteed to stay unique.
As usual with bookmarklets, just right click on the link and “save link as” or drag it into your bookmarks toolbar.
I know, I know, it’s not all that impressive, but I’m proud of my little bookmarklet. As I keep telling Dustin and my other
133t Hax0r friends, I’m a designer, not a coder. Now feel free to pick it apart and tell me what you would have done differently and I’ll update the link above accordingly.
14 comments on “CSS CacheBuster”
Awesome tip! Now I don’t have to click on refresh twice or use cache cleaner no more.. 😉
How about just hitting Control + Refresh?
Good point Dennison. I should have mentioned that above. Ctrl+Refresh (IE) and Shift+Refresh (Firefox) are handy if the caching issue is client-side, but my issue was server-side so unfortunately that didn’t work.
Seems reasonable, It’s just too bad designers/developers don’t deploy solutions for this by default. That would make the readers job much easier.
Instead of using an URI of “style.css?foo”, using a random number would be more efficient.
IMHO, the best way to handle the caching process of css and js is to serve them with Perl/PHP/… You can then set the cache parameters by sending the right header.
Server side caching is the bane of my life at times. I have come across some implementations of pages (php) on apache servers where the use of ?x after the URL or the external links (like above) just doesn’t work at all. The page still gets cached and the externals. The only way around this I have found, please someone tell me a better way. Is to call an include that generates a server processor request (random number will do). You don’t have to use the number generated, just do the server process.
This technique is quite good, unless you use, as in my case, query parameters to determine how the css to be parsed.
Even then it’s good for applying multiple skins on the same css file, which is what I do.
To sum up — use the technique only if the css is not server side generated and is GET parameter dependent.
This has been an absolute lifesaver.
Many, many thanks.
We will see how it works in practice…
My understanding is that every time you want to force a reload of CSS (or any static file) you need the change the value that is after the ?. so ?version=1 and then ?version=2 and so on.
if the value is always the same the browser can still think it has screen.css?foo because that was what the file was called last time.
I’ve also tried to detail a similar approach on my own site. The bookmarklet is a great touch for developing.
Adding ?foo was the solution my coworkers came up with when they were manually editing the stylesheet link, and yes, occasionally the server will actually cache a stylesheet with the same query string value. The bookmarklet actually adds a timestamp (for instance ?1187096080951) to the link url, and therefore is always unique.
Your bookmarket is great 😉 even if you are designer 😉
Thanks for sharing how to deal with server side caching. I really thought this was well written.
The technique described doesn’t guarantee a predictable outcome when your application is exposed to the internet. Some intermediate agents, like older versions of Squid ignores the query string, so http://www.example.com/main.js?foo and http://www.example.com/main.js?foo2 is treated as http://www.example.com/main.js. Then there are cases, where the intermediate agents may never cache something with a query string (since it may be considered to be dynamic).
The only way to reliably bust the cache is to change the path, change http://www.example.com/main-213.js to http://www.example.com/main-627.js