必须在html中成对设置img的width和height整数像素值(如width="320" height="180"),仅靠css的width、height或aspect-ratio无法有效降低cls,因浏览器解析html时无法读取css值,需原生属性提前预留空间。

img的width和height属性必须成对写在HTML里
只靠CSS设置width和height或aspect-ratio,对降低CLS基本没用。浏览器解析HTML时根本“看不见”CSS里的值,只能靠HTML原生width和height属性提前算出宽高比,预留准确空间。
常见错误是:在Vue/React里用:style="{ width: '100%' }"动态控制,或者只写height="480"漏掉width——这两种都会触发CLS。原因很简单:没有宽高两个整数像素值,浏览器无法推导出稳定宽高比。
-
width和height必须都是整数,比如width="320" height="180",不能是"100%"或"auto" - 响应式场景下,可用
srcset配合sizes,但width/height仍要填原始尺寸(即图片文件本身的像素值) - 现代Safari(iOS 16.4+)开始支持
aspect-ratio,但老版本Safari、微信内置浏览器、部分iframe嵌入页仍会忽略它,不能当主力方案
video和iframe也要预留空间
<video></video>和<iframe></iframe>同样会引发CLS,尤其嵌入第三方视频或地图时。它们不像<img>有原生width/height属性,得靠CSS强制占位。
推荐用aspect-ratio + width: 100%组合,兼容性比单纯padding-bottom方案好:
video, iframe {
width: 100%;
aspect-ratio: 16 / 9; /* 必须是数字比,不能写 "16:9" */
max-width: 100%;
}
注意:aspect-ratio在Chrome 88+/Firefox 89+/Edge 91+可用,但Android WebView旧版(如WebView 75)不支持,此时需回退到padding-bottom技巧。
- 避免用
height: 300px固定高度——不同屏幕宽度下会被拉伸或裁剪 - 第三方
iframe(比如YouTube)如果无法控制源码,至少用loading="lazy"延后加载,减少首屏突变 -
<video></video>加preload="metadata",让浏览器提前读取时长和尺寸信息
字体切换导致的CLS容易被忽略
手机端Web Font加载慢,浏览器先用系统字体渲染,等自定义字体就绪后重绘,文字高度/行高变化直接引发下方内容跳动。这不是图片问题,但CLS贡献不小。
解决核心是:不让字体切换影响布局。
- 用
font-display: optional或swap,但optional更激进——字体加载超时就永不替换,彻底规避重排 - 给文本容器设
line-height和min-height,用系统字体的典型行高(如1.4)做兜底 - 避免用
em或rem做line-height基准,改用无单位数值(如line-height: 1.4),防止字体切换时放大缩小 - 慎用
font-size-adjust,虽能保持x-height一致,但兼容性差(仅Chrome/Firefox支持)
懒加载图片的时机很关键
loading="lazy"本身不引发CLS,但若图片进入视口时还没加载完,浏览器会用0×0占位,加载完成瞬间撑开空间——这正是CLS高发点。
真正安全的懒加载,必须配合占位策略:
- 所有
<img>必须带width和height,哪怕懒加载也得写 - 用
placeholder(如base64小图)或纯色背景,确保占位块高度固定 - 避免在滚动中频繁触发
IntersectionObserver回调,可加rootMargin: "100px"提前加载,减少“闪跳” - 服务端渲染(SSR)页面中,
loading="lazy"可能被忽略,需检查HTML输出是否真带该属性
CLS不是单点问题,是多个占位失效叠加的结果。手机端屏幕窄、字体渲染差异大、第三方脚本注入多,任何一个环节漏掉width/height或没控住字体重排,都可能让CLS从0.05飙到0.3以上。别信“加个aspect-ratio就万事大吉”,老机型、微信浏览器、低配安卓机还在用十年前的渲染逻辑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











