先把当时的情况摆出来。Next.js 14 的文章页改用 next/image,字段加上了 width 和 height,PSI 移动端 CLS 仍是 0.19,红点在正文第一张大图的位置。图片加载完成后正文被整体往下推了 180px,桌面端只有 0.03。一开始以为是字体换行造成的,把 font-display 换成 optional 也没动。
原因不止一个,得分开看。容器写了 max-width:100% 但没写 height:auto,属性里的比例在 CSS 里被覆盖了。还有一种是图片外面套了一层没有高度的 div,占位由图片撑开,加载前高度是 0。
还有一种情况,srcset 里竖版图在窄屏被选中,宽高比和属性里写的不同。另外,懒加载把首屏图也包了进去,占位框要等 IO 回调才替换。
先看 CLS 归因里具体是哪个元素在位移
npx lighthouse https://www.example.com/p/1024 --only-audits=layout-shifts --view
给图片容器补上宽高比占位
style="aspect-ratio:4/3;width:100%;height:auto"
接着确认首屏图没有走懒加载
grep -n 'loading=' components/ArticleHero.tsx
末了用固定视口多测几次,确认位移值收敛
npx lighthouse https://www.example.com/p/1024 --form-factor=mobile --throttling-method=simulate
恢复的判定其实很直接。三次移动端测试的 CLS 都在 0.02 以下,位移列表里不再出现那张主图,阅读时正文也不再跳。
提醒一点。宽高写对但 CSS 里把 height 设成具体像素,同样救不回来,占位比例最终由渲染后的盒子决定。这类问题最好一次改到位,反复小改反而容易把原因搅混。
