service worker 缓存 css 的关键是 install 阶段预缓存且路径与 html 中 link href 完全一致;fetch 事件需判断 event.request.destination === 'style';更新需处理 sw 生命周期;@import 和 url() 不被拦截,须单独缓存;推荐用内容哈希文件名确保路径三者对齐。

Service Worker 缓存 CSS 文件的最小可行写法
直接能用、不报错的关键是:在 install 阶段预缓存,且路径必须和 HTML 中 <link rel="stylesheet"> 的 href 完全一致(包括斜杠、查询参数、大小写)。
常见错误是把 styles.css 写成 /styles.css 或漏掉 ?v=1.2,导致浏览器请求时找不到匹配缓存,回退到网络——看起来“没生效”。
- 缓存策略建议用
CacheFirst(优先读缓存),CSS 一般不常变,且首次加载后几乎不会重请求 - 务必在
fetch事件中加判断:event.request.destination === 'style',避免误缓存图片或脚本 - 示例片段:
self.addEventListener('fetch', event => {
if (event.request.destination === 'style') {
event.respondWith(
caches.match(event.request).then(res => res || fetch(event.request))
);
}
});
CSS 缓存更新不生效?检查 SW 注册与激活时机
Service Worker 不会自动更新已激活的缓存。用户刷新页面时,新 SW 只注册、等待旧 SW 控制页数归零才激活;而旧缓存仍被复用,导致改了 CSS 却看不到效果。
根本原因不是缓存逻辑写错了,而是生命周期没理清。
立即学习“前端免费学习笔记(深入)”;
- 开发阶段可调用
navigator.serviceWorker.getRegistration().then(r => r?.update())强制检查更新 - 上线后推荐在
waiting状态时提示用户刷新,或调用skipWaiting()(需确保 CSS 更新是向后兼容的) - 调试时打开 Chrome DevTools → Application → Service Workers,勾选 “Update on reload”,再硬刷(Ctrl+Shift+R)
imported CSS(@import)会被 SW 自动缓存吗?
不会。Service Worker 只拦截主文档发起的网络请求,@import 是 CSS 解析器内部行为,触发的请求不会经过 SW 的 fetch 事件。
这意味着:只缓存了 main.css,但它里面写了 @import "theme.css",后者仍走网络,失去离线能力。
- 解决办法只有两个:把
@import拆成 HTML 中多个<link>,或用构建工具内联(如 PostCSS 插件) - 注意:CSS 中的
url()(比如字体、背景图)同理不被 SW 拦截,需单独列入缓存列表 - 验证方式:Network 面板里看
Size列是否显示from cache,而非from ServiceWorker
缓存 CSS 时要不要加版本前缀或哈希?
要,但不是为了“让缓存失效”,而是为了“让缓存更稳”。SW 缓存靠 URL 做 key,如果总用 styles.css,每次部署都得手动清旧缓存或跳过等待,容易出错。
更可靠的做法是让文件名本身带内容哈希,比如 styles.a1b2c3.css,这样新旧版本天然隔离,无需额外清理逻辑。
- 构建工具(Vite/Webpack)默认支持
filenameHashing: true,输出带哈希的 CSS 文件 - SW 脚本里缓存列表也得同步用这个带哈希的路径,不能写死
styles.css - 别用时间戳或版本号(如
styles.css?v=2.1)——CDN 或中间代理可能忽略查询参数,导致缓存穿透
真正麻烦的从来不是怎么存 CSS,而是怎么确保 HTML 加载时用的路径、SW 缓存的路径、构建输出的路径三者始终对齐。稍有脱节,就变成“以为缓存了,其实没生效”。








