缓存清除 CSS 的策略

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 $200 免费积分!

从浏览器缓存 CSS 中可以获得重大性能提升。您可以确保您的 服务器已设置 以发送指示浏览器将 CSS 文件保留一定时间的标头。这是许多(如果不是大多数)网站已经在执行的最佳实践。

与浏览器缓存并存的是 _缓存清除_。假设浏览器将 CSS 文件缓存了一年(并不罕见)。然后您想更改 CSS。您需要一种策略来清除缓存并强制浏览器下载 CSS 的新副本。

以下是一些方法。

CSS 必须被缓存,这样才有效……

为了确保这一点,以下是一些看起来很健康的缓存 CSS 文件标头

我们要找的是 `Cache-Control` 和 `Expires` 标头。我不是服务器配置专家。我可能会看看 H5BP 服务器配置。但以下是一些经典的 Apache/HTAccess 方法来实现这一点

<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)(\.gz)?$">
  Header set Expires "Thu, 15 Apr 2020 20:00:00 GMT"
</FilesMatch>
<IfModule mod_expires.c>
  ExpiresActive on
  ExpiresByType text/css                  "access plus 1 year"
  ExpiresByType application/javascript    "access plus 1 year"
</IfModule>

查询字符串

如今大多数浏览器都会将带有不同查询字符串的 URL 视为不同的文件并下载新副本。大多数 CDN 甚至 支持并推荐 此操作。

<link rel="stylesheet" href="style.css?v=3.4.1">

进行微小的更改?将其更改为

<link rel="stylesheet" href="style.css?v=3.4.2">

您可以通过设置一个服务器端变量并在多个地方使用它来简化操作。因此,更改它将同时清除许多文件的缓存。

<?php $cssVersion = "3.4.2"; ?>

<link rel="stylesheet" href="global.css?v=<?php echo $cssVersion; ?>">

也许您甚至可以使用 语义版本控制。您还可以 定义一个常量

更改文件名

查询字符串并不总是有效。一些浏览器不会将不同的查询字符串视为不同的文件。有些软件(我听说:Squid)不会缓存带有查询字符串的文件。Steve Souders 告诉我们不要这样做

一个类似的概念是更改文件名本身。例如,在 HTML 中

<link rel="stylesheet" href="style.232124.css">

您会以编程方式处理它,而不是在项目中真正更改文件名。由于该文件实际上不存在于服务器上,因此您需要执行一些技巧才能将其路由到正确的文件。Jeremy Keith 最近介绍了他的技术,它可以实现这种操作。

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+).(\d+).(js|css)$ $1.$3 [L]

这告诉服务器忽略 JavaScript 和 CSS 文件名中的这些数字,但只要我更新该数字,浏览器仍然会将其解释为新文件。

他使用 Twig,因此他使用的模板最终就像

{% set cssupdate = '20150310' %}

<link rel="stylesheet" href="/css/main.{{ cssupdate }}.css">

我相信您可以想象任何后端语言中都会有类似的版本(例如 ASP)。通过创建构建工具或部署脚本来更新变量本身,您可以更上一层楼。

将缓存清除“数字”基于文件更新日期

在搜索有关缓存清除的内容时,您会看到很多建议,建议您使用服务器检查文件最后更新的时间以创建缓存清除“数字”(数字,即用于清除缓存的任何内容)。

function autoversion($url) {
  $path = pathinfo($url);
  $ver = '.'.filemtime($_SERVER['DOCUMENT_ROOT'].$url).'.';
  return $path['dirname'].'/'.str_replace('.', $ver, $path['basename']);
}
<link href="<?php autoversion('/path/to/theme.css'); ?>" rel="stylesheet">

我对此并不了解。在我看来,让服务器在每次页面浏览时都查找此信息会非常密集,在生产环境中很危险。过去我曾做过一些事情,比如“我只需要让 PHP 在数据属性中输出图片的尺寸!”结果却发现它把服务器搞得停滞不前。总之,小心为妙。

ETags

ETags 看起来是个好主意,因为它们的重点是检查浏览器是否已经拥有该文件的副本的信息。

但大多数建议都说:“关闭 ETags 标头”。雅虎 表示

ETags 的问题是它们通常使用使它们对托管站点的特定服务器唯一的属性构建。当浏览器从一台服务器获取原始组件,然后尝试在另一台服务器上验证该组件时,ETags 不会匹配,这种情况在使用服务器集群来处理请求的网站上太常见了。

另一个问题是它们不像实际缓存那样有效。为了检查 ETag,仍然需要进行网络请求 才能进行验证。影响性能的不仅仅是下载文件,还有所有网络协商和延迟问题。

同样,我不是专家,但以下是在 Apache 中通常建议关闭它们的方法

<IfModule mod_headers.c>
  Header unset ETag
</IfModule>
FileETag None

框架会帮我们做

Rails 资产管道

我对 Rails 资产管道Sprockets 有点经验。在我看来,这是一个非常理想的系统。我在模板中链接样式表

<%= stylesheet_link_tag "about/about" %>

它会生成类似以下内容的 HTML 代码

<link href="http://assets.codepen.io/assets/about/about-7ca9d3db0013f3ea9ba05b9dcda5ede0.css" media="screen" rel="stylesheet" type="text/css" />

只有当文件更改时,缓存清除数字才会更改,因此您只会清除需要清除的文件的缓存。此外,它还包含用于图像和 JavaScript 的方法。

WordPress

如果您在 WordPress 中使用 _页面_ 缓存工具,例如 W3 Total Cache 或类似工具,您可能就不必太担心 `filemtime` 业务过于占用服务器资源。

Gilbert Pellegrom 发布了一篇关于 WordPress 特定技术的文章,使用它

wp_register_style( 'screen', get_template_directory_uri().'/style.css', array(), filemtime( get_template_directory().'/style.css' ) );
wp_enqueue_style( 'screen' );

// Example Output: /style.css?ver=1384432580

WordPress 插件 Busted! 在后台做同样的事情。只是它会自动地对所有内容进行操作。

CodeKit

CodeKit 没有内置的方法来更改文件名,但它确实提供了一种方法可以在您设置的环境下执行 Shell 脚本。

Michael Russell 有一篇关于如何在文件中注入时间戳的博客文章,我相信您可以修改它来改为更改文件名。

构建工具

所有流行的任务运行器/构建工具都有插件可以帮助更改文件名。Sufian Rhazi 有一篇文章 介绍了如何在原生 Node.js 中执行此操作。

Grunt

Gulp

Broccoli

预处理器中

在将资产链接到其他资产时(例如,从 LESS 文件中链接的图像),可以使用预处理器来处理。 Ben Nadel 发表了一篇文章,介绍了如何使用这种方法。

异步 CSS

随着关键 CSS 的流行,延迟加载 CSS 变得越来越普遍。 还有其他一些延迟加载 CSS 的原因(例如,打印 CSS 或缓存预取)。

如果您使用 loadCSS(或者可能是 注入链接标签)加载 CSS,则需要在 JavaScript 本身中更新它所请求的文件名。 这与更改文件名不同,但并不完全不同。

所以

还有哪些我漏掉了? 您的缓存清除策略是什么?