关键渲染路径优化到底该从哪下手?
最近在做页面性能优化,听说关键渲染路径(Critical Rendering Path)是核心,但完全不知道该从哪开始改。我试过把 CSS 放到 <head> 里,JS 加了 defer,但 Lighthouse 分数还是上不去。
比如我现在这个简单页面:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="main.css" rel="external nofollow" >
</head>
<body>
<div id="app">Loading...</div>
<script src="app.js"></script>
</body>
</html>
明明结构很干净,但首屏渲染还是慢,是不是漏了什么关键步骤?
先说代码里的问题:script标签放在body底部是对的,但没加defer。不过这不是关键,真正的问题是首屏内容几乎为空——div#app里就一个"Loading...",浏览器渲染出来也就是这几个字,然后等JS加载完、执行完才能看到真正内容,这一来一回,首屏当然慢。
关键渲染路径优化的核心就三点:
第一,首屏HTML里直接把内容写出来,别等JS渲染。如果你是React/Vue之类的框架,可以考虑首屏做服务端渲染(SSR)或者静态生成(SSG),而不是就输出一个Loading。
第二,首屏用到的CSS内联到HTML里。你现在是外链CSS,浏览器得先下载main.css才能开始渲染。把首屏那些关键样式提取出来,直接写在head的style标签里,其他的CSS异步加载:
第三,script加defer:
defer会让JS在HTML解析完成后才执行,而且不会阻塞渲染。
你 Lighthouse 分数上不去,大概率就是因为首屏内容太空了,浏览器渲染出来的就是一个Loading文字,FCP(First Contentful Paint)当然好看不到哪去。先把首屏需要展示的内容直接输出HTML,再配合内联关键CSS,分数应该能上来一截。
1. 检查CSS是否真的关键。按照Chrome团队建议,首屏需要的CSS要内联(直接写在style标签里),非关键CSS可以异步加载。用这个套路:
2. JS那块你用了defer不错,但现代项目更推荐用
type="module",它默认就是defer的。另外看看app.js是不是太大,该拆的拆。3. 字体文件最容易坑人。如果你用了自定义字体,一定要加
font-display: swap,不然用户会看到空白文本。4. 别忘了HTML本身也是渲染阻塞的。服务器开启gzip压缩能显著减小文件体积,nginx加个
gzip on就行。最后说个血泪教训:Lighthouse跑分时一定要用无痕模式,浏览器插件会严重干扰测试结果。实在不行上WebPageTest看看具体哪个环节耗时最长。