One of the items benchmarking tools like GTMetrix and Google PageSpeed Insights rate your site for, is whether it leverages browser caching or not.
Often these tools reveal more pressing matters to concern yourself with, that have a larger impact on the benchmarking score. Practices like optimizing images and minifying CSS, HTML, and JavaScript, for instance.
On the other hand, I’m not a server-side expert, but I found that achieving a better score on these tools – and getting a slightly faster page load – by adding just a couple of lines to your .htaccess
file to enable browser caching is quite simple.
Here’s how I did it.
How does browser caching work
Your site contains files that change often and some that change not so often. Some files hardly – if ever – change.
When you place an image on your site, that image will almost never change. Same with video files. JavaScript files, like those that your theme or plugins use, change more often. PDF files also tend to change more often.
CSS files generally change most often, especially when you’re a designer or developer. Visitors need a fresh copy of those on their computer since CSS files change the look of your site.
When a person visits your site, their browser downloads these files and saves them on their hard drive. Plus, for each of these files, the browser sends a separate request to the server. This all adds to a load of your server, slowing it down. Especially image files and video add to the load.
With browser caching turned on, not all of these files will be requested and downloaded again when your visitor clicks on another page on your site that uses the same files or revisits your site later. Their computer uses the stored files instead of downloading the same files again. This practice helps your site load faster for that visitor since these downloaded files and file requests don’t need to be transferred over the internet again.
By the way, the effect of browser caching on page loading times depends greatly on the size of your pages. When your site is image-heavy, and the visitor’s browser needs to download large files from your site, the effect is greater than when your site takes a more minimalist approach.
Now, adding browser caching doesn’t totally solve the issue these tools report. Some external .js files, like Google Analytics and Google Fonts, do not allow caching, but your site will score better with browser caching enabled.
It took me a long time to figure out the best caching setup for my WordPress sites on Apache servers. And I am open to changes in the future when technology changes.
How do you add browser caching to your site’s setup
Browser caching rules tell the browser whether a file only needs refreshing once a year, once a month, or whatever time you decide is appropriate for your situation. Refreshing, in this case, means downloading it again.
The rules that tell the browser when to download which files are set in the .htaccess
file in the root of your site.
Note: messing around in your .htaccess
file is a great way to bring your site down. Always, always, always make sure you download a copy of your working .htaccess
file before you change anything in the file.
Using Expires
headers for browser caching
Until recently, I used the recommended settings GTmetrix prescribes on their site.
For these settings, GTmetrix takes the approach that:
- image and video files change least often, so these will download again after a year since the last downloaded version
- JavaScript, and PDF files change a little more frequently, so these will download after a month
- CSS files change most often, so need downloading after a week
- all other files will download again after a month
Caveat: I noticed some problems with forms on a site using a general one-month expiry, so I took that rule out.
# BROWSER CACHING USING EXPIRES HEADERS
<IfModule mod_expires.c>
ExpiresActive On
# Images
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType image/x-icon "access plus 1 year"
# Video
ExpiresByType video/mp4 "access plus 1 year"
ExpiresByType video/mpeg "access plus 1 year"
# CSS, JavaScript
ExpiresByType text/css "access plus 1 week"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
# Others
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType application/x-shockwave-flash "access plus 1 month"
</IfModule>
The solution GTmetrix prescribes uses Expires
headers that specify expiration times for specific file extensions to the browser. This way, the browser knows when to download a fresh copy of a specific file.
When added to the .htaccess
file, these rules turn on browser caching without any problems.
However, there is another – and apparently better – way.
Using Cache-Control
headers for browser caching
I recently came across this article on using Cache-Control
headers for browser caching.
Cache-Control
headers replaces Expires
headers is more flexible (accepts more directives), and is currently the preferred method for browser caching.
Since all modern browsers support Cache-Control
headers, you should only need to add these lines to your .htaccess
file:
# BROWSER CACHING USING CACHE-CONTROL HEADERS
<ifModule mod_headers.c>
# One year for image and video files
<filesMatch ".(flv|gif|ico|jpg|jpeg|mp4|mpeg|png|svg|swf|webp)$">
Header set Cache-Control "max-age=31536000, public"
</filesMatch>
# One month for JavaScript and PDF files
<filesMatch ".(js|pdf)$">
Header set Cache-Control "max-age=2592000, public"
</filesMatch>
# One week for CSS files
<filesMatch ".(css)$">
Header set Cache-Control "max-age=604800, public"
</filesMatch>
</ifModule>
As you can see, I’m using the exact same file expiration settings in these Cache-Control
headers as in the Expires
headers example. All max-age values are in seconds, e.g. one month equals:
60 (seconds in a minute) x 60 (minutes in an hour) x 24 (hours in a day) x 30 (average number of days in a month) = 2592000
According to the Google Developers site, Cache-Control
headers are all we need:
The Cache-Control header was defined as part of the HTTP/1.1 specification and supersedes previous headers (for example, Expires) used to define response caching policies. All modern browsers support Cache-Control, so that’s all you need.
Google Developers website
Fail-safe method for setting browser caching in your .htaccess file
However, Dutch hosting provider Byte describes using both Expires
headers and Cache-Control
headers on their servers, to ensure proper browser caching on servers that may not support one. This might, for now, be the fail-safe method of choice, and what I’m using for my own and my client’s sites:
# BROWSER CACHING USING EXPIRES HEADERS
<IfModule mod_expires.c>
ExpiresActive On
# Images
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType image/x-icon "access plus 1 year"
# Video
ExpiresByType video/mp4 "access plus 1 year"
ExpiresByType video/mpeg "access plus 1 year"
# CSS, JavaScript
ExpiresByType text/css "access plus 1 week"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
# Others
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType application/x-shockwave-flash "access plus 1 month"
</IfModule>
# BROWSER CACHING USING CACHE-CONTROL HEADERS
<ifModule mod_headers.c>
# One year for image and video files
<filesMatch ".(flv|gif|ico|jpg|jpeg|mp4|mpeg|png|svg|swf|webp)$">
Header set Cache-Control "max-age=31536000, public"
</filesMatch>
# One month for JavaScript and PDF files
<filesMatch ".(js|pdf)$">
Header set Cache-Control "max-age=2592000, public"
</filesMatch>
# One week for CSS files
<filesMatch ".(css)$">
Header set Cache-Control "max-age=604800, public"
</filesMatch>
</ifModule>
Disabling ETag: yes or no
The Byte article also recommended disabling ETag
by adding these lines to the .htaccess
file:
# REMOVE AND DISABLE ETAG
Header unset ETag
FileETag None
# Remove Last-Modified
Header unset Last-Modified
However, when I did that, GTmetrix told me to specify a cache validator, stating:
All static resources should have either a Last-Modified or ETag header. This will allow browsers to take advantage of the full benefits of caching.
GTmetrix
… and punished me in their validation. For a client’s site, it cost me about 4% on their Page Speed Score, so I took it out quickly!
Teaches me not to mess with a good thing when I don’t know exactly what I’m doing
What are your recommended browser caching settings, and why do you do it the way you do it? Add your thoughts and/or settings in the comments below.
Resources
- Caching Tutorial for Web Authors and Webmasters (Mark Nottingham)
- PageSpeed: Leverage browser caching (GTmetrix)
- Expires Header en Cache-Control (Byte – Dutch)
- HTTP caching (Google Developers)
- Cache-Control – HTTP (MDN)
Want more tutorials?
Check here