上个月我们给一个开发者工具站做 CLS 整改,从 0.31 降到 0.09,用了一周。动的是 168 个没写尺寸的图片和 6 个嵌入组件。方法不新鲜,难的是把全站扫干净,一个都别漏。
图片:给每个 img 补上宽高
CLS 的根源是浏览器不知道元素最终多大,等内容到了再撑开。宽高属性是成本最低的修法,现代浏览器会拿这两个数自动算宽高比、预留空间。
<img src="dashboard.webp" width="1440" height="810" alt="产品后台截图" loading="lazy">
有了这两个属性,图片下载前就能按 16:9 占位。响应式图片再配上 sizes 和 srcset,占位比例依然成立。
查法:跑一遍全站爬虫,把没有 width 和 height 的 img 列出来。我们这个站 312 张图里有 168 张缺尺寸,主要来自博客正文和客户案例页,编辑器上传时没做校验。
嵌入组件:iframe 也要占位
地图、演示视频、客服 iframe 经常从 0 高度起步,加载完撑到 400 多像素。改法是外层容器写死比例,iframe 填满容器。
.embed { aspect-ratio: 16 / 9; width: 100%; }
.embed iframe { width: 100%; height: 100%; border: 0; }
这个站的定价页嵌了三个客户评价视频,原来每个都从 0 撑到 320 像素,改完位移归零。顺手把 YouTube 的嵌入换成 youtube-nocookie 加懒加载,首屏也轻了一点。
骨架屏要预留真实高度
骨架屏高度和真实内容不一致,等于位移换了个形式。我们的做法是拿一次真实数据截图量出高度,骨架屏写死这个值,误差控制在 8 像素以内。这个站的后台截图区差了 120 像素,改完才真正消掉。
广告位和推荐位
有广告或者合作推荐的站,位子必须提前占好。常见做法是给容器一个 min-height,里面没内容时也占着。这个站的博客文末有一条合作推荐,原来从 0 撑到 180 像素,用户读到最后一行时正文被推走,改完加了 min-height 就好了。
这类位子的另一个问题是内容有时不来,占位就一直空着。我们一般给个 3 秒超时,超时后容器收起,收起动作放在用户看不见的区域,不影响 CLS。
验收方式
改完别只看 Lighthouse。用 Chrome Performance 面板录一次移动端加载,看 Experience 轨道还有没有位移;再等两周看 GSC 的真实数据。这个站实验室数据第一天就到 0.02,真实数据两周后稳定在 0.09,差距来自长尾页面——旧博客里有 40 多张历史图片还在漏。
我们给客户定的验收标准是两件事同时满足:实验室三次测试都在 0.1 以下,真实数据两周后 P75 在 0.1 以下。只看前者容易自欺,只看后者周期太长,项目会拖。
最后提醒一句:公众号文章和富文本编辑器粘进来的图片最容易漏。我们的做法是在编辑器上传环节强制写入宽高,从源头堵住,不然三个月后又会冒出来。
元析智能
为软件公司做 SEO 和 GEO 优化