第一眼要检查index.html中<link>的href是否含哈希,如assets/style.abc123de.css;若仍为assets/style.css,则构建配置未生效或被覆盖,需核对Vite/Webpack哈希配置、Tailwind content扫描及CDN/服务端缓存策略。

检查HTML中引用的CSS文件名是否带Hash
生产环境CSS没更新,第一眼要盯住 index.html 里 <link rel="stylesheet"> 的 href 地址。如果还是 assets/style.css 这种固定名字,浏览器缓存就永远不会失效——哪怕你重新构建了10次。
正确做法是确保构建后 CSS 文件名包含内容哈希,比如 assets/style.abc123de.css。Vite 默认开启 build.rollupOptions.output.assetFileNames 配置,Webpack 则需显式设 contenthash;若用 Tailwind CLI 手动构建,得确认命令里加了 --content 且输出路径带哈希(否则 PurgeCSS 会删掉样式,连文件都生成不出来)。
- 打开浏览器开发者工具 → Network → 刷新页面 → 找到那个 CSS 请求,看响应头
Cache-Control和实际 URL 是否含哈希 - 对比
dist/目录下真实生成的 CSS 文件名,和 HTML 中写的是否一致 - 如果 HTML 里仍是无哈希路径,说明构建配置没生效,或被自定义插件覆盖(比如某些 SSR 模板硬编码了资源路径)
验证HTTP缓存头是否允许浏览器重验
即使文件名变了,如果服务器给 CSS 返回了 Cache-Control: max-age=31536000(一年),浏览器仍可能跳过请求直接读缓存——但这时它找的是旧哈希名,自然 404 或加载失败。
关键不是“禁用缓存”,而是让浏览器在每次访问时都发一次 HEAD 或带 If-None-Match 的请求去校验。这需要服务端配合:
立即学习“前端免费学习笔记(深入)”;
- 静态资源(JS/CSS)应返回
Cache-Control: public, max-age=31536000, immutable(前提是文件名含哈希) - HTML 文件必须返回
Cache-Control: no-cache或max-age=0,否则用户永远拿不到新 HTML,也就加载不了新 CSS - Nginx 示例:
location ~* \.(js|css|png|jpg|gif)$ { add_header Cache-Control "public, max-age=31536000, immutable"; }
排查Tailwind或PurgeCSS误删样式
很多“CSS丢失”根本不是缓存问题,而是构建时压根没生成对应规则——尤其 Tailwind v3+ 启用 JIT 后,content 配置漏路径、动态 class 没进 safelist,会导致生产包里根本没有 text-red-500 这类样式,浏览器就算加载了新 CSS,也渲染不出。
快速验证:打开 DevTools → Elements → 找一个该有样式却没生效的元素 → 看 computed 样式里有没有对应规则;再切到 Sources → 找到加载的 CSS 文件 → Ctrl+F 搜索类名,确认是否存在。
- 检查
tailwind.config.js的content数组是否覆盖所有含 class 的文件,包括.vue、.tsx、public/index.html,甚至node_modules中第三方组件路径 - 动态拼接类名(如
class="text-${color}-500")必须写进safelist,正则比字符串列表更可靠:{ pattern: /text-(red|blue|green)-500/ } - 用
@apply的自定义样式,必须包裹在@layer components块内,否则扫描器识别不到依赖关系
确认CDN或反向代理是否缓存了旧HTML
最隐蔽的坑:你以为刷新了页面,其实看到的是 CDN 缓存的旧 index.html,里面还引用着上个版本的 CSS 哈希名。这时候清本地缓存、硬刷新都没用。
验证方式:直接访问 HTML 资源的完整 URL(比如 https://cdn.example.com/index.html?_t=xxx),看源码里 link 的 href 是不是最新哈希;或者 curl -I 查响应头里的 Age 和 X-Cache 字段。
- CDN 配置需对
index.html设置极短缓存(如max-age=60),并开启基于查询参数或 ETag 的缓存失效 - 如果用了 Nginx 作反向代理,确认没配
proxy_cache_valid 200 1h这类针对 HTML 的长缓存 - 上线后立即执行一次 CDN 缓存刷新(不是预热),尤其当 HTML 文件名不变时
真正卡住人的往往不是技术点本身,而是多个环节的缓存叠加:CDN 缓了 HTML,浏览器缓了旧 CSS,而构建又漏扫了 class —— 三者一齐发力,问题就变得“随机出现、无法复现”。动手前先分层验证:从网络请求看 URL 是否新、从响应头看缓存策略是否合理、从源码看 CSS 内容是否真存在。


















