核心在于读写分离:先集中读取所有布局属性(如offsetheight、getboundingclientrect),再批量执行样式修改(如style.width、classlist.add),避免交替触发强制同步布局,从而防止频繁重排导致帧率抖动。

核心在于把“读布局”和“写样式”彻底拆开,不混在同一轮 JS 执行中——浏览器才能把写操作批量推迟到下一帧前统一处理,避免反复触发回流(reflow)。
为什么混着读写会抖动
当你连续执行类似这样的代码:
- element.offsetHeight(读:强制浏览器立刻计算当前布局)
- element.style.width = '300px'(写:又要求改布局)
浏览器只能中断渲染流水线,当场重排一次;紧接着下一行再读再写,又来一次。几十次下来,帧率直接跌破 30fps,肉眼可见卡顿。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
怎么真正实现读写分离
不是简单加个 setTimeout 就行,关键在**顺序控制**:
- 所有读取布局的操作(offsetTop、getBoundingClientRect()、clientWidth 等)集中放在一个代码块里,一次性读完
- 所有修改样式的操作(style.xxx、className、setAttribute('style', ...))全部挪到读取之后,且尽量批量完成
- 如果必须在读之后立即写,可用 getComputedStyle(element).height 替代 clientHeight,它不会触发强制布局
配合 CSS 和 API 效果更稳
光靠 JS 顺序还不够,得从渲染机制上绕开布局计算:
- 动画类变更优先用 transform 和 opacity,它们走合成线程,不触发布局
- 需要频繁更新的元素,提前加 will-change: transform,让浏览器提前升层
- 涉及滚动定位逻辑(比如吸顶导航),直接用 position: sticky,比 JS 切换 fixed 更安全,不引发页面高度跳变
验证是否生效的小技巧
打开 Chrome DevTools → Rendering 面板 → 勾选 “Layout Shift Regions” 和 “FPS Meter”,然后滚动或交互:
- 如果红色闪烁区域大幅减少、FPS 曲线平稳在 55–60 之间,说明读写分离起效了
- 若仍有频繁黄色 Layout 条,说明还有隐藏的同步读写没切干净,重点检查第三方库或事件回调里的 DOM 访问










