事情本身不复杂,线索都在日志里。移动端在 window 上绑了 scroll 监听做吸顶效果,每次滚动都同步读 offsetTop,CrUX 里 INP 280ms,卡顿集中在首屏交互。

第一反应是「jQuery 动画和原生滚动事件混用,主线程排队」,验证下来不成立。

排查方向其实有限,先把可能性排一排。scroll 回调里同步读取布局属性,触发强制重排。少数情况下是监听没有节流,滚动一次触发几十次计算。

少数情况下是第三方埋点也在 scroll 里执行,叠加后超过 200ms。

录制一段滚动看长任务

chrome --headless --trace-startup --duration=5 https://www.example.com/

再往下把回调改成节流并设 passive

sed -i 's#window.addEventListener("scroll", onScroll)#window.addEventListener("scroll", throttled, {passive:true})#' theme/js/app.js

吸顶改由 CSS 负责

sed -i 's#position: relative; top: 0#position: sticky; top: 0#' theme/assets/css/header.css

等前面都确认过,再检查是否还有同步布局读取

grep -rn 'offsetTop' theme/js/ | head

白天有业务在跑,能验证的部分都压到了晚上做。

恢复的判定其实很直接。INP 从 280ms 降到 150ms 以内,滚动时主线程的长任务数明显减少,字段数据在四周内跟进。

容易忽略的是,sticky 能省掉整段 JS,但父容器有 overflow hidden 时会失效,改前先确认祖先元素。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189