你点开自己写的页面,正想读第一段,结果文字“唰”一下往下跳——配图还没出来,按钮已经滑出屏幕了。不是网卡,不是手抖,是页面在你眼皮底下偷偷改版。

这感觉谁没经历过?CLS 就是那个总在关键时刻捣乱的隐形 Bug。

为什么图片加载完总让你的页面“抖一下”?

浏览器看到 <img> 标签时,如果没写 widthheight,它根本不知道这张图要占多大地方。等图一加载完,“砰”地塞进来,后面所有内容全被往下顶。

响应式图片更狡猾。你写了 width: 100%,但没管高度,手机上图被压成方块,标题直接被挤走。用户刚扫到第三行字,图一到位,视线瞬间断掉。

解决办法很简单:每张图都补上 widthheight 属性。
如果是现代项目,CSS 里加一句 img { aspect-ratio: 16/9; width: 100%; height: auto; } 就够了。浏览器提前知道比例,留好位置,图再慢,页面也不晃。

字体加载导致的布局偏移怎么彻底解决?

字体文件大、加载慢,浏览器只能先用系统字体撑着。等自定义字体一落地,每个字的宽高重算,整段文字“缩”或“胀”,连带周围元素一起位移。

有家知识付费站首页用了三套字体,每次打开,标题、正文、按钮轮流跳,用户说:“像在看PPT翻页。”

别硬扛。两个实用方案:

  • 关键位置(比如 Logo、主标题)用 font-display: block,宁可等一会儿,也要留足空间;
  • 正文、说明文字这类非视觉焦点,直接上 font-display: optional,100ms 内没加载成功就放弃,全程用系统字体——不美,但稳。

顺手把字体 <link rel="preload"> 也加上,让它抢在 HTML 解析完就开下。

动态插入内容时,如何避免页面“跳楼式”偏移?

广告、推荐栏、评论区、弹窗……这些内容不是一开始就有的。它们在 DOM 里突然冒出来,就像有人在你读到最后一句时,猛地往你脚底下塞了块砖——页面“咚”一下沉下去。

最典型的是广告。你预留了 300×250 的坑位,广告返回个 300×600 的横幅,整个版面直接变形。更糟的是,有些广告等你滚动到一半才加载,正文当场被掀翻。

做法很实在:

  • 所有异步内容,先用一个固定尺寸的容器占位。尺寸不确定?至少设个 min-height,别让它空着塌掉;
  • 广告容器加 overflow: hiddenmax-height,超出部分裁掉,不许它乱伸腿;
  • 评论区这类长内容,初始状态用骨架屏占位,高度和最终内容一致,数据来了再填进去。

还有 Cookie 弹窗——别让它等页面渲染完再蹦出来。要么 position: fixed 脱离文档流,要么在 <body> 顶部预留一块固定高度区域,让它有地儿落。

滚动条的出现和消失,为什么会引发连锁位移?

很多人完全没意识到这事有多烦人。
列表页内容少,没滚动条;点进详情页,内容一长,滚动条“啪”地弹出来,占掉 17px 宽度。所有文字块被迫重排,换行点变了,图片被挤扁,布局跟着晃。

页面切换时这种抖动最隐蔽,用户可能没察觉,但 CLS 分数已经爆表。

解法就一行 CSS:

html { overflow-y: scroll; }

强制滚动条常驻。宽度恒定,布局就不会被它反复拿捏。

交互动画和过渡效果,如何避免产生CLS?

注意:用户点下去之后 500ms 内发生的动画,浏览器默认不计入 CLS。这是你的安全窗口。

但很多“自动动画”卡在灰色地带。比如滚动到某处,侧边栏自动滑出;或者定时器一到,通知框弹上来——这些没人点,浏览器照记不误。

正确姿势是:所有非交互触发的动效,只用 transformopacity

  • 想让元素滑入?写 transform: translateY(-20px)transform: translateY(0),别碰 topmargin-top
  • 想淡入?只调 opacity,别改 visibilitydisplay
    这两个属性不触发布局重排,再炫的动效,CLS 也纹丝不动。

今天就能执行的3个CLS修复动作

别等“大版本优化”。现在打开电脑,花 15 分钟,立刻见效。

  1. 打开 Chrome DevTools → Lighthouse → 点“生成报告”。选中“Performance”,跑一次。报告里会标出所有 Layout Shift 区域,重点看图片、广告位、字体加载前后。截图存好,这就是你今天的靶子。

  2. 打开你网站任意一个文章页的源码(右键 → 查看页面源代码),搜 <img,挨个检查有没有漏掉 widthheight。没有的,补上;响应式图,在 CSS 里给 img 加上 aspect-ratio

  3. 打开 Chrome DevTools → Elements 面板,展开 <body>,滚动页面,观察哪些区块是后来插入的(比如 #ad-banner.related-posts.cookie-banner)。找到它们的父容器,在 CSS 里给它加个 min-height: 200px(数值按实际预估),确保它始终占位。

做完这三步,你页面的“抽搐感”会明显缓解。字体和滚动条的问题可以放明天下午茶时间顺手处理。CLS 不是玄学,就是一个个具体元素的位置管理——你盯住它们,它们就不敢乱动。