关键CSS文件被阻塞首屏渲染怎么办?

Newb.钰欣 阅读 36

我在优化首屏加载时发现,即使把CSS文件压缩到5KB,页面仍然会卡在“render”阶段。尝试过把CSS内联和使用都没效果,用Lighthouse检查显示这个CSS还是关键路径的一部分,该怎么让它不影响首屏渲染?

代码结构是这样的:<link rel="stylesheet" href="/styles/main.css" rel="external nofollow" rel="external nofollow" >,里面包含了整个项目的样式。我试着把首屏需要的样式抽出来做成critical.css,但合并到HTML后其他页面样式反而乱了。


<!-- 现在的HTML结构 -->
<head>
  <style>/* 内联的critical样式 */</style>
  <link rel="stylesheet" href="/styles/main.css" rel="external nofollow"  rel="external nofollow" >
</head>

用Chrome开发者工具的Coverage标签发现,main.css有80%未使用的代码,但不知道怎么安全地拆分而不影响布局。有没有更好的拆分策略或配置方法?

我来解答 赞 8 收藏
二维码
手机扫码查看
2 条解答
开发者佳佳
问题应该出在你虽然抽离了首屏关键CSS,但 main.css 仍然是渲染阻塞资源,并且体积大、冗余多,浏览器还是会下载它才能完成完整渲染。光内联 critical CSS 不够,必须解决 main.css 的加载方式和内容拆分。

第一步,确认你现在用的 critical CSS 真的是首屏最小必要样式。可以用 Puppeteer 或 Chrome DevTools 手动录一次首屏快照,提取 body 前几屏元素用到的 CSS 规则。别靠猜,很多人内联的 critical 实际包含了非首屏类名。

第二步,对 main.css 做代码分割。既然 Coverage 显示80%未使用,说明你项目用了组件化但打包时全量引入了。比如你用了 Tailwind 或 Bootstrap 这类框架,得开 purge 功能。Tailwind 要配 content 字段扫描模板文件,Bootstrap 如果是自己引入的 SCSS,就只 import 需要用的模块,别直接引全部。

第三步,把 main.css 改成异步加载。你现在是普通 link 标签,会阻塞。改成这样:

<link rel="preload" href="/styles/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles/main.css"></noscript>


或者更简单的用 loadCSS 方案:

<link rel="prefetch" href="/styles/main.css" as="style">


配合 JS 异步注入:

function loadCSS(href) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
document.head.appendChild(link);
}
// 页面加载完再加载非关键CSS
window.addEventListener('load', () => loadCSS('/styles/main.css'));


第四步,按路由或页面拆分 CSS。如果你有多个页面,不要共用一个 main.css。用构建工具比如 Webpack 或 Vite,把样式按 page 分离,首页只加载 home.css,用户页加载 user.css。Vite 里用 dynamic import 或 splitChunks 就能实现。

最后,上线前用 Lighthouse 再跑一遍,看“Eliminate render-blocking resources”这条是否消失。如果还有卡顿,检查 network 面板里 main.css 是否和其他关键资源争抢带宽,可以加 media 属性降优先级:

<link rel="stylesheet" href="/styles/main.css" media="print" onload="this.media='all'">

这样至少不会抢占首屏渲染。
点赞 8
2026-02-09 08:02
欧阳卜楷
代码给你,直接上方案。

你遇到的问题是典型的关键CSS阻塞渲染。既然你已经用Lighthouse检查过,那你也知道需要提取首屏关键CSS,但你没拆分好,导致样式乱套。解决方案分两步走:拆分CSS + 延迟加载非关键CSS。

先用工具帮你抽首屏CSS。我常用的是puppeteer + critical库,本地跑个脚本:

const critical = require('critical');

critical.generate({
inline: true,
base: 'dist/',
src: 'index.html',
target: {
css: 'styles/main.css'
},
dimensions: [{
width: 1920,
height: 1080
}]
});


这会帮你提取首屏用到的CSS,并且内联到HTML里。main.css剩下的是非关键CSS,可以延迟加载。

然后在HTML里这样处理:

<head>
<style>/ 这里是critical CSS /</style>
<link rel="stylesheet" href="/styles/main.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/styles/main.css"></noscript>
</head>


注意media="print"是为了不让浏览器默认加载这个CSS,然后用onload="this.media='all'"来触发加载。noscript是为了兼容没开JS的情况。

这样拆完之后,main.css就不再是渲染阻塞资源了。Lighthouse再跑一遍,应该会好很多。

最后别忘了加个CSS加载器优化体验:

function loadCSS(href) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
document.head.appendChild(link);
}


页面加载完后再加载其他CSS,或者根据路由加载对应样式。这样就能真正拆干净了。
点赞 2
2026-02-06 13:13