图片缺width和height属性时浏览器按0×0占位,加载后撑开容器致下方内容下移,是最高频cls来源;应使用aspect-ratio配合width实现响应式占位,或回退html宽高属性。

图片没写 width 和 height 属性,浏览器渲染时就按 0×0 占位,等图片加载完成才撑开容器,下方所有内容瞬间下移——这是最直接、最高频的 CLS 来源。
为什么图片缺宽高必然引发跳动
浏览器解析 HTML 是流式进行的。遇到 <img src="a.jpg"> 这种没尺寸的标签,它无法预知这张图多大,只能先分配一个“看不见的 0×0 区域”。等图片数据真正下载并解码完成,渲染引擎才重新计算布局,把父容器高度从 0 拉到实际像素值(比如 800px),于是原本紧贴在图片下方的文字、按钮、卡片全部被往下顶,用户眼里的效果就是“页面突然沉了一下”。
- 这个偏移只要发生在视口内,且元素有可见面积,就会被 Layout Instability API 记录为一次 layout shift
- 哪怕只跳 10px,如果是一整屏横幅图,影响分数可能高达 0.5 以上,远超 0.1 的推荐阈值
- CSS 里用
width: 100%; height: auto或max-width: 100%完全无效——浏览器仍不知道原始宽高比,占位逻辑不变
用 aspect-ratio 实现响应式占位
现代方案是用 aspect-ratio 配合宽度控制,在不牺牲响应性的前提下提前锁定容器比例。浏览器据此能算出高度,无需等待图片加载。
- 写法示例:
<img src="a.jpg" style="max-width:90%"> - 关键点:必须同时有
width(或max-width)和aspect-ratio,否则容器宽度不定,比例也无从生效 -
object-fit控制内容填充方式,避免拉伸变形;aspect-ratio本身不依赖图片资源,CSS 解析阶段就参与盒模型计算 - 兼容性注意:Safari 15.4+、Firefox 89+、Chrome 88+ 支持良好;旧版 Safari 可降级回传统 width/height 属性
别忽略 srcset 和第三方 iframe
即使用了 srcset + sizes 做响应式图片,也必须配原始 width 和 height 属性。否则浏览器可能先按默认尺寸(如 300×150)占位,等选中高清资源后再重排,造成两次跳动。
- YouTube、TikTok 等嵌入 iframe 同理:必须显式写
width="560" height="315",loading="lazy"不解决占位问题 - 若需完全响应式且兼顾兼容,可用内联 style 写
min-height(如style="min-height: 315px;"),数值取历史平均高度 - 服务端渲染或静态生成时,建议从图片元信息中提取宽高,自动注入 HTML 标签属性
字体加载也会引发类似跳动
跟图片逻辑相似:用 font-display: swap 虽能快速显示文本,但系统字体和自定义字体的行高、字宽差异大会导致文字块高度突变,下方内容照样被顶下去。
- 解决方案是在
@font-face中加size-adjust: 102%(数值需实测微调),让备用字体尽可能逼近目标字体的度量 - 关键容器如
<h1></h1>、按钮建议预设line-height和min-height,防止字体切换时高度塌缩或撑开 - 避免在
font-family列表里混用等宽与比例字体(如"Monaco", "Helvetica"),ch/ex 单位行为不一致会放大偏移风险











