硬件加速本质是绕开主线程重排重绘,仅走GPU合成:transform和opacity能触发独立合成层,后续变化只挪图层、调透明度;混用left或background-color等属性则整段退化CPU渲染。

硬件加速不是“GPU更快”,而是绕开主线程卡点
动画卡顿的根源,从来不是GPU算力不够,而是浏览器把动画任务塞进了主线程——每次改left或top,都要重排(layout)→ 重绘(paint)→ 合成(composite),三步全走完才能出一帧。低端 Android WebView 里,一帧内多次重排直接堵死主线程。
真正起作用的是:transform和opacity能触发浏览器创建独立的**合成层(Compositing Layer)**,后续变化只走最后一步(composite),由合成线程在 GPU 上直接挪图层、叠透明度,跳过前两步。这不是“加速”,是“绕路”。
-
transform: translateX(100px)→ 挪已有图层,几毫秒搞定 -
left: 100px→ 重新算位置、重画像素、再合成,耗时翻倍 - 混用属性会降级:比如
transition: left, transform 0.3s,整段回退到 CPU 渲染
哪些 CSS 属性真能触发硬件加速
只有特定属性被浏览器识别为“可合成”,才会建层。别信transition: all——它大概率让你的动画更慢。
- 安全项(稳定触发合成层):
transform(含translateX、scale、rotate,但matrix()等非标准写法可能失效)、opacity - 伪 3D 项(老设备兜底用):
transform: translateZ(0)、transform: translate3d(0,0,0)、perspective: 1000px - 滤镜类(谨慎用):
filter: blur(2px)(单个简单滤镜有效,链式叠加如blur(1px) contrast(1.2)可能回退) - 明确无效项:
box-shadow、width、height、margin、background-color—— 它们动一次就重绘
will-change不是开关,是提示器
will-change: transform不是“打开硬件加速”的魔法咒语,它只是提前告诉浏览器:“这玩意儿马上要动了,请提前建层”。现代浏览器(Chrome 80+ / Safari 14+)已能自动判断何时建层,静态写死反而有害。
立即学习“前端免费学习笔记(深入)”;
- ✅ 正确用法:JS 在
touchstart时设el.style.willChange = 'transform',监听transitionend后立刻设回'auto' - ❌ 错误用法:
.item { will-change: transform; }—— 所有.item 一加载就建层,列表页容易 OOM -
backface-visibility: hidden和perspective主要解决旧 Android 设备闪烁,新机型基本不用加
JS 读布局会悄悄毁掉所有优化
哪怕 CSS 全写对了,只要动画过程中 JS 做了以下操作,就会触发**强制同步布局(Forced Synchronous Layout)**,让合成线程等主线程交出 layout 结果,一帧卡死。
- 读取返回布局信息的属性:
offsetTop、getBoundingClientRect()、scrollHeight - 读写交替:
console.log(el.offsetTop); el.style.transform = 'translateX(100px)'; - 在
requestAnimationFrame回调里混入布局读取 - 正确做法:批量读取 → 批量写入;或用
ResizeObserver/IntersectionObserver替代轮询查询
合成层数量没上限,但内存和显存有。Chrome DevTools 的 Layers 面板才是你该盯住的地方,而不是盲目加translateZ(0)。


















