H5 CSS 动画与渲染性能
H5 CSS 动画与渲染性能
动画能够帮助用户理解页面状态变化,但实现不当会造成掉帧、耗电增加和滚动卡顿。浏览器每一帧可能经历脚本执行、样式计算、布局、绘制和合成。优化动画的关键,是尽量缩小每帧需要重新计算的范围,并避免主线程长任务阻塞下一帧。
一、理解渲染阶段
不同 CSS 属性会触发不同工作:
- 改变尺寸和位置关系,通常会触发布局。
- 改变背景、阴影等视觉属性,通常需要重新绘制。
- 改变变换和透明度,在合适条件下可主要由合成阶段处理。
因此,移动元素时优先考虑 transform,淡入淡出优先考虑 opacity,比每帧修改 left、top 或宽高更容易保持流畅。
二、使用 transform 完成位移动画
.panel {
transform: translateY(100%);
transition: transform 240ms ease-out;
}
.panel.is-open {
transform: translateY(0);
}
动画前后状态由类名表达,JavaScript 只负责切换状态,不需要每帧计算位置。
持续时间应遵循项目动效规范。过长动画会拖慢操作,过短又无法表达空间关系。
三、避免同时读取和写入布局
读取元素尺寸后立即修改样式,再读取下一个元素,会迫使浏览器反复刷新布局。
const heights = cards.map(card => card.getBoundingClientRect().height);
cards.forEach((card, index) => {
card.style.setProperty('--measured-height', `${heights[index]}px`);
});
先集中读取,再集中写入,可以减少强制同步布局。更理想的情况是通过正常 CSS 布局解决,不在脚本中测量。
四、按帧合并视觉更新
滚动和指针移动可能在一帧内触发多次,视觉更新可以通过 requestAnimationFrame 合并。
let framePending = false;
let latestProgress = 0;
function updateProgress(progress: number): void {
latestProgress = progress;
if (framePending) return;
framePending = true;
requestAnimationFrame(() => {
indicator.style.transform = `scaleX(${latestProgress})`;
framePending = false;
});
}
这保证一帧最多执行一次 DOM 写入,同时使用最新值。业务数据仍可逐次处理,合并的是视觉刷新。
五、谨慎使用 will-change
will-change 可以提示浏览器某个属性即将变化,但长期给大量元素设置会占用额外内存和合成资源。
.dragging-card {
will-change: transform;
}
它适合在动画开始前短暂添加,结束后移除。不要把 will-change 写进所有通用组件作为永久优化。
六、控制阴影、滤镜和遮罩
大范围模糊、复杂阴影和实时滤镜可能产生较高绘制成本,尤其在低端移动设备上。动画过程中改变这些属性更昂贵。
可以考虑缩小效果区域、减少模糊半径、使用静态视觉资源或只在动画结束状态显示复杂效果。是否替换必须结合设计要求和性能测量,不能只凭属性名称判断。
七、不要动画到 auto
从固定高度过渡到 auto 缺少明确数值,传统过渡无法直接插值。常见展开面板可以使用网格轨道、最大高度上限或脚本测量,但每种方案都有边界。
如果内容高度变化频繁,脚本测量要处理字体加载、图片加载和窗口变化。简单场景也可以使用即时展开配合透明度,不必为了视觉效果引入脆弱的高度估算。
八、尊重减少动态效果设置
部分用户会在系统中开启减少动态效果。页面应降低非必要位移和缩放,同时保留状态反馈。
@media (prefers-reduced-motion: reduce) {
.panel,
.loading-indicator {
animation-duration: 1ms;
animation-iteration-count: 1;
transition-duration: 1ms;
}
}
减少动画不等于删除所有反馈。可以用颜色、文本和即时显隐表达结果。
九、动画结束状态要可靠
业务逻辑不应完全依赖动画结束事件才能完成关键提交,因为元素移除、用户设置或浏览器调度都可能改变事件行为。动画应装饰已经确定的状态,而不是成为业务状态唯一驱动者。
需要在动画后清理类名时,可以监听结束事件,并在组件销毁时解除监听。连续触发动画还要取消旧状态,避免多个结束回调互相覆盖。
十、验证真实设备表现
桌面设备流畅不代表移动设备流畅。测试应覆盖:
- 低端设备上的连续打开和关闭。
- 页面滚动同时运行动画。
- 大量列表项同时变化。
- 横竖屏与视口尺寸变化。
- 减少动态效果设置。
- 动画中途切换页面或销毁组件。
使用性能时间线观察每帧中的脚本、布局、绘制和合成占比,才能确定实际瓶颈。
总结
流畅 CSS 动画需要减少每帧工作。优先使用变换和透明度,批量读写布局,按帧合并高频更新,并谨慎使用合成提示和复杂视觉效果。动画还应尊重用户偏好,并始终从属于可靠的业务状态。
- 点赞
- 收藏
- 关注作者
评论(0)