为什么我的CSS文件在网络面板中总是比JS文件后加载?

公孙爱玲 阅读 54

在开发项目时发现页面加载时样式闪一下,检查Network面板发现styles.css显示完成时间比app.js还晚,但HTML里link标签确实在script标签前面:

<link rel="stylesheet" href="styles.css" rel="external nofollow" >
<script src="script.js" async>

我已经尝试过移除async属性和调整加载顺序,但Network里CSS仍然显示在JS后面完成,这是怎么回事?

我来解答 赞 19 收藏
二维码
手机扫码查看
2 条解答
闲人美菊
这个问题其实是个经典误解,我来帮你理清楚。

首先,你观察到的Network面板里的"完成时间"顺序,和HTML里的声明顺序完全是两码事。

浏览器解析HTML时,遇到 <link> 标签会发起CSS请求,遇到 <script> 标签会发起JS请求。但是,你的JS加了 async 属性,这意味着它会完全异步加载,不阻塞任何东西。而CSS本身也是异步下载的(不会阻塞HTML解析),但它会阻塞渲染。

关键点来了:现代浏览器都有"预扫描"机制。浏览器在正式解析HTML构建DOM树之前,会先快速扫描一遍HTML,把里面所有的外部资源链接都找出来,然后尽可能并行发起请求。所以实际上,你的CSS和JS几乎是在同一时间发起请求的,而不是像你以为的那样"先请求CSS,等CSS完了再请求JS"。

你在Network面板里看到JS比CSS先完成,大概率是因为你的JS文件比CSS文件小,或者JS所在的服务器响应更快。这跟HTML里的书写顺序没关系。

再说那个"样式闪一下"的问题,这才是你真正要解决的。这个现象叫FOUC(Flash of Unstyled Content),原因是浏览器在CSS还没加载完的时候就先把没样式的HTML渲染出来了。

解决方案有几个思路。

第一,把关键CSS内联到HTML里。把首屏必须的样式直接写在 <style> 标签里,这样浏览器不用等外部CSS就能渲染出基本样式。

<head>
<style>
/* 关键样式内联,比如布局骨架、背景色、字体 */
body { margin: 0; background: #fff; font-family: system-ui; }
.header { height: 60px; background: #333; }
.main { min-height: 100vh; }
</style>
<link rel="stylesheet" href="styles.css">
</head>


第二,如果你不想内联,可以在 <head> 里加一个简单的加载状态遮罩,等CSS加载完再显示内容。

<head>
<style>
.page-loading { position: fixed; inset: 0; background: #fff; z-index: 9999; }
.page-loaded .page-loading { display: none; }
</style>
</head>
<body>
<div class="page-loading"></div>
<!-- 页面内容 -->
<link rel="stylesheet" href="styles.css" onload="document.body.classList.add('page-loaded')">
</body>


第三,检查你的服务端配置。如果CSS文件很大,考虑开启HTTP/2或者做文件压缩,CSS文件传输慢才是导致加载时间长的根本原因。你可以在Network面板里看一下CSS的TTFB和Content Download时间,哪个长就优化哪个。

具体来说,如果TTFB长,那是服务器响应慢,考虑CDN加速;如果Content Download长,那是文件太大或带宽问题,考虑压缩、拆分文件。

另外补充一点,你的JS用了 async,这个属性会让脚本在下载完立即执行,不管HTML解析到哪了。如果你的JS里有操作DOM的代码,可能也会导致页面闪烁或重排。如果JS需要操作DOM且你希望它按顺序执行,应该用 defer 而不是 async

<!-- defer保证脚本在HTML解析完后、DOMContentLoaded之前按顺序执行 -->
<script src="script.js" defer></script>


总结一下:Network面板里的顺序不用纠结,那是网络层面的东西。你要关注的是渲染层面的优化,把关键样式内联、或者用loading状态过渡,才是解决闪烁的正确姿势。
点赞 1
2026-03-01 13:04
程序员梦轩
这个问题我之前踩过坑,说白了就是浏览器的加载机制和你的代码执行方式在打架。先说结论:虽然你在HTML里把标签写在