为什么我的页面CLS总是很高,明明没做什么动态内容?

技术风云 阅读 34

最近用Lighthouse测性能,发现累积布局偏移(CLS)分数特别差,经常超过0.25。我页面里其实没加什么广告或者异步图片,就是普通的商品列表,每个商品有个标题和价格。

我试过给图片加了固定宽高,也用了aspect-ratio,但CLS还是不稳定。有时候刷新一下就高,再刷又正常了,完全搞不懂是哪里在动。有没有可能是字体加载导致的?我用的是Google Fonts。

我来解答 赞 7 收藏
二维码
手机扫码查看
2 条解答
Tr° 亚楠
这个问题我太熟悉了,十有八九就是字体加载搞的鬼。你已经排除了图片和动态内容,那CLS不稳定大概率是字体切换时产生的跳动。

先说说原理:浏览器加载Google Fonts的时候,默认行为是先显示fallback字体(比如系统默认的宋体/黑体),等web字体下载完再替换成你指定的字体。这一替换,文本的宽高就变了,周围的元素自然就被挤来挤去,CLS就上去了。而且因为网络情况不同,有时候快有时候慢,所以你的CLS分数时高时低。

解决思路有几个,按我说的顺序来试:

第一步:加上font-display属性,这是最快最有效的办法。在Google Fonts的link里加上display=swap参数:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=你的字体&display=swap" rel="stylesheet">


display=swap的意思是:字体下载期间先用fallback字体显示,下载完成后立刻换成目标字体。这样虽然可能有轻微的字体切换感,但至少不会产生大幅度的布局偏移。

第二步:如果第一步不够,或者你想更讲究一点,可以预加载字体。把它放在HTML的最前面,让浏览器提前开始下载:

<head>
<link rel="preload" href="https://fonts.googleapis.com/css2?family=你的字体" as="style">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
...
</head>


第三步:如果你的字体切换后文字大小差异很大,还可以调整fallback字体。用CSS的size-adjust让fallback字体和目标字体更接近,这样切换时视觉差异小:

@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2');
font-display: swap;
ascent-override: 90%;
descent-override: 20%;
size-adjust: 95%;
}


这几个参数需要你根据实际情况微调,ascent-override和descent-override控制字体的上下留白,size-adjust整体缩放fallback字体。

你可以先从第一步开始试,一般就能解决大部分问题了。如果还有问题,再配合第二步第三步。
点赞
2026-03-11 19:09
设计师景岩
你这个情况我太熟悉了,十有八九就是 Google Fonts 的字体加载问题,尤其是中文字体文件特别大,加载时会先显示一个系统字体(比如 Helvetica 或 Arial),等字体加载完了再突然切换成你指定的字体,导致文字高度、宽度变化,CLS 就崩了。

先确认下是不是这个原因:打开 DevTools 的 Network 面板,勾选 Disable cache,然后刷新页面,看字体文件是不是在首屏就加载,而且加载时间比较长(比如超过 200ms)。

解决方案很简单,给字体加 font-display: swap,再配合 preconnectpreload,代码给你:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Your+Font:wght@400;700&display=swap" rel="stylesheet">


CSS 里别忘了写 font-display: swap,如果你是用 Google Fonts 的链接,其实加了 display=swap 就自动生效了,但保险起见你可以在 CSS 里再确认下:

body {
font-family: 'Your Font', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-display: swap; /* 如果是通过 CSS @import 的话 */
}


不过更推荐用 link 标签引入,别用 @import,后者会阻塞渲染。

另外,如果你页面里有动态插入的元素(比如某个 JS 300ms 后才插入一个广告位或者提示条),也会导致 CLS 飙升,建议用 Chrome 的 Performance 面板录一段加载过程,看 Layout Shift Regions 里具体是哪块在动,一般都能定位到。

实在不行,临时加个:

* {
max-lines: 3; /* 或者用 min-height / min-width 固住容器 */
}


把可能塌陷的区域先占位住,也能缓解,但治标不治本,还是优先解决字体加载的问题。
点赞 6
2026-02-24 16:11