There were lots of great comments on the CSS Caching article. I learned a lot from those comments, so I wanted to clear up some of the misunderstanding and highlight some of the great tricks other folks shared.
- It is the browser that does the caching, but the server can have some say in the matter. Many browsers will first ask the server whether or not it needs to download the CSS again and the server will respond. Sometimes the server will respond with a 304 (Not Modified) which will tell the browser to just use its own cached copy. Apparently, if you change you CSS on the server and almost instantly refresh the browser, the server may not have caught up yet and will respond with a 304 and your browser will used its cached copy. (Thanks Eric)
- You can alter your server settings (if you are using Apache) to “expire” CSS files after one second. See 2nd Comment. This will achieve the same effect as timestamping, because the browser will always tell browsers that it should download the CSS fresh. (Thanks Joshua)
- If you are using versioning software of any kind, adding version info to the end of the CSS link is probably a smarter way of handling this. (Thanks August)
- Instead of appending the exact date and time to the end of the CSS link, appending the date and time of the last time file was modified is even smarter. Try this instead echo filectime(’/path/to/style.css’); This also returns a timestamp instead of a “human readable” date, which will eliminate the spaces in the URL link. (Thanks …everyone!)
- Remember that you can SHIFT-Refresh in most browsers to force it to re-download all the files it needs. This one is easy enough to explain to your clients even! (Thanks Paul)
When switching between pages of a site many browsers won’t go back to the server for a CSS file at all, although most make a request when refresh is pressed.
Appending a querystring to the CSS file will prevent the browser using the cache, but this shouldn’t be used on a live site. Even if the querystring remains the same requests some browsers will always go for a fresh copy from the server. I believe Opera and Safari do this, as per the http spec.
From ftp://ftp.isi.edu/in-notes/rfc2616.txt
—
We note one exception to this rule: since some applications have traditionally used GETs and HEADs with query URLs (those containing a “?” in the rel_path part) to perform operations with significant side effects, caches MUST NOT treat responses to such URIs as fresh unless the server provides an explicit expiration time. This specifically means that responses from HTTP/1.0 servers for such URIs SHOULD NOT be taken from a cache.
—
The best way is to set a far-future expiry on CSS files and change the URL when the data changes, without using a querystring. You can achieve this with mod_rewrite or by physically changing the filename of the CSS file.
css/style1.css
…make a change…
css/style2.css
The unique part of the filename could be a timestamp of the file’s modified date, and mod_rewrite would make style\d+.css point to style.css.
That way, the user’s always getting the newest version of your CSS without throwing caching out the window.
Jake.
On the note about the interactions between the browser and server, Jake is correct that the browser does not always ask the server for a new stylesheet (especially Opera) if the file has an EXPIRE header of -1 or some date in the future.
EXPIRE-ing the CSS files after one second is one way to make sure that your users’ CSS is current, and there are many more headers like PRAGMA=no-cache and others for this.
One of the best ways I have found is from Yahoo’s suggestion: setting an ETag header to the filename + time of the file. I can’t tell you all the ways to configure your server to do this but you now have something to Google for and a starting place.
Hope that helps! Thanks for the update Chris!
The shift-refresh totally made my morning. I’ve been trying to figure out a way to do that for the longest!
for all those short-cut lovers: CTRL + F5 will also force download all files on a webpage.
I have been developing somthing of the same kind for Javascript files. Recently I have completed my Javascript aggregator for the “Zend Framework” wich compiles a seperate file per combination of Javascript files.
Now how is this interesting? The identifier to check wether an combination is already compiled and cached is a md5 checksum of the composed body from all files. This way if the contents of one file are changed the key changes and a new file is send from the server, otherwise the file isn’t requested again.
Iam currently trying something similar for CSS files as well, ill try too keep you guys informed.
What I forgot to mention is that the md5 checksum is the filename that gets loaded instead of 5 seperate files.
Honestly guys, personally i tend to go for the technique where i rename the files like so ::
now i don’t even use the v var in the code, hell im not even looking into the get params to check if its even there. but the browser! oh it thinks its a whole new dimention it has to explore and forgets caching all together :)
also this way you always know what version of the file your at. i created an engine once that manipuated the value for ‘v’ based on changes happening in the filesystem. kind of a basic svn of sorts,as it was lossless. :) be well all