HTML中img和iframe必须带width/height属性,浏览器解析时若缺失则按0×0占位,资源加载后重排导致下方内容下移,是CLS飙升最常见原因;仅CSS宽高无效,响应式需组合HTML属性与CSS样式,并为动态内容预留min-height占位容器。

HTML中图片和iframe必须带width和height属性
浏览器解析HTML时,若<img>或<iframe>缺失内联width和height,会按0×0占位;资源加载完成后再重排,直接导致下方内容下移——这是CLS飙升最常见、最确定的来源。仅靠CSS设置宽高完全无效。
- 响应式场景下,可写
<img src="x.jpg" width="600" height="400" style="width: 100%; height: auto;">,既满足HTML尺寸声明,又保留弹性缩放 - 使用
srcset+sizes时仍需配width/height,否则浏览器可能先按默认尺寸占位,再调整,造成两次偏移 -
loading="lazy"不能替代尺寸声明——两者必须共存,否则YouTube嵌入、广告iframe等必触发偏移
动态内容注入前必须在HTML源码中预留占位容器
JS动态插入广告、评论、推荐模块时,若目标区域为空,新节点一挂载就会把原有内容往下顶。Lighthouse常将这类问题归因于<body>,实际根源是HTML里没写占位结构。
- 服务端或构建阶段就写好固定高度容器:
<div id="ad-slot" style="min-height: 250px;"></div>,高度尽量基于历史均值或服务端预估 - 避免用
visibility: hidden或opacity: 0占位——它们不脱离文档流,但无盒尺寸,等于没占 - 骨架屏(Skeleton)应作为HTML初始结构的一部分,而非JS渲染后才插入;用
replaceWith()替换,而非innerHTML =重写整个容器
字体加载引发的文本重排要从HTML+CSS协同控制
自定义字体加载期间用系统字体渲染,加载完成后切换,若两套字体行高、字宽差异大,文本块高度突变,就会推挤下方内容。这不是纯CSS问题,而是HTML中<style>或<link>引入时机与字体声明方式共同决定的。
-
@font-face中必须设font-display: swap,禁用optional(它可能导致字体反复切换,CLS更糟) - 关键文本容器(如
<h1>、CTA按钮)应在HTML中预设style="line-height: 1.5; min-height: 2em;",防止字体切换时容器塌缩或撑开 - 避免在
font-family列表中混用等宽与比例字体(如"Monaco", "Helvetica"),ch/ex单位行为不一致,易引发宽度跳变
第三方脚本注入节点必须被HTML容器主动包裹
Google Ads、客服Widget等第三方脚本常在DOMContentLoaded后异步注入DOM,且不提供尺寸约束。它们是CLS黑盒来源,但你可以在HTML层提前“画框”收容它们。
立即学习“前端免费学习笔记(深入)”;
- 为广告位写
<div class="third-party-wrapper" style="min-height: 200px;"></div>,再让JS把广告插入该容器内部 - 对跨域
<iframe>,用aspect-ratio配合position: absolute布局:<div style="position: relative; aspect-ratio: 16/9;"><iframe style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe></div> - Nuxt/Next等框架中,
v-if或useState触发的组件挂载,父容器也必须有明确min-height或aspect-ratio,否则hydration后仍会抖



















