手机发热主因是浏览器用CPU反复重绘整层,关键要让动画跑在GPU合成线程且不触发Paint;box-shadow、filter、background-image等属性改动会强制重绘,仅transform/opacity也不够,需隔离图层、限时迭代、降载释放纹理。

直接结论:手机发热不是动画“太炫”,而是浏览器被迫用CPU反复重绘整层——关键得让动画跑在GPU合成线程上,且全程不触发Paint。
哪些CSS属性一动就让手机发烫
box-shadow、border-radius、filter: blur()、background-image(尤其未压缩PNG)、gradient 这些属性改一次,浏览器就得重画整个图层,CPU逐像素算阴影扩散或抗锯齿,安卓低端机瞬间升温。实测一个带 box-shadow 的 transition 动画,帧率常跌破20fps,手机比充电器还烫。
-
box-shadow和filter: drop-shadow()别混进动画里,哪怕只加1px模糊半径,整段动画就退化回CPU渲染 -
background-image改尺寸或滚动中缩放,会反复重采样;全屏<img>比background-image更耗内存,解码开销大 -
border-radius在动画中配合transform时,圆角抗锯齿计算量陡增,尤其在Android WebView v6.8以下
为什么只用 transform/opacity 还是烫
光写 transform: translateX(100px) 不等于进了GPU流水线——只要混入任意非合成属性,或JS偷偷读布局,就立刻破防。
- 别写
transition: all 0.3s,它会让color、border等也加过渡,无谓触发重绘 - 绝对不要同时写
transform: translateX(100px); top: 20px;—— 后者直接让浏览器放弃图层优化 - 动画中调一次
getBoundingClientRect()或offsetHeight,就会强制同步layout,帧率断崖下跌 -
will-change: transform静态写在CSS里等于让浏览器永远建独立图层,低端机容易OOM卡死
怎么让动画真正走GPU且不烧机
核心是“隔离+限时+降载”:把动画元素提成独立合成层,限制迭代次数,空闲时停掉并释放纹理。
立即学习“前端免费学习笔记(深入)”;
- 对要动的元素,用
transform: translateZ(0)或transform: translate3d(0, 0, 0)强制建层,但别全局加,只加在明确要动的节点上 - 把
animation: fade 3s infinite改成animation-iteration-count: 3,避免无限调度合成任务 - 监听
animationend后立刻执行el.style.willChange = 'auto';iOS Safari可能不触发该事件,需加setTimeout(() => ..., duration + 100)兜底 - 动画暂停时,用
element.style.animationPlayState = 'paused'并重置transform到初始值,释放GPU纹理 - 避免对
position: fixed元素狂刷transform,部分Android机型会丢失锚点,造成抖动+额外重绘
容易被忽略的物理层陷阱
再好的CSS优化也架不住硬件被堵死——动画本身不烫,但滚动时 fixed 导航栏反复重绘、overflow: hidden 截断图层提升、微信X5内核忽略 will-change,都会让CPU满载。
- 页面有
body { overscroll-behavior: contain }时,吸顶栏滚动重绘更频繁,优先考虑用position: sticky替代fixed - 父容器设了
overflow: hidden或clip-path,会阻止子元素图层提升,transform也救不了 - 旧版微信X5内核(v6.8以下)对
opacity动画仍触发Paint,得搭配动态加will-change: opacity才生效 - infinite 动画 + 全屏
<img>是发热组合拳,内存纹理不释放,GPU持续喂帧——改成background-image+background-size: cover能省一半功耗


















