缓冲动画在 Safari 上为啥不流畅?
我最近在做一个加载状态的缓冲动画,用的是 CSS 动画配合 transform,Chrome 和 Firefox 都挺顺滑的,但在 Safari 上明显卡顿,甚至有时候直接不动了。是不是我哪里写得不对?
我试过加 will-change 和 translateZ(0) 但都没啥用。下面是动画的关键部分:
.spinner {
width: 40px;
height: 40px;
border: 3px solid #f3f3f3;
border-top: 3px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
border动画的渲染确实有点拉胯。问题出在 Safari 处理
border旋转时的合成层策略上。你用border搭配border-radius: 50%画圆,再让整个元素旋转,Safari 会频繁触发重绘而不是走 GPU 合成,性能就崩了。我来给你说下解决方案。
最稳妥的方案是改用 SVG 来做这个 spinner,SVG 动画在 Safari 上性能表现好很多,因为它天生就是矢量图形,渲染路径更优化。
这个方案在 Safari 上跑得飞起,因为 SVG 的
stroke动画走的是 GPU 加速路径,不会像border那样疯狂重绘。如果你不想改 HTML 结构,只想用纯 CSS 撑着,还有个折中方案是用伪元素加
clip-path:这里需要注意,
transform: translateZ(0)要加在伪元素上而不是父元素上,因为真正在动的是这些伪元素的 border 渲染层。不过说实话,SVG 方案还是更靠谱,我们项目里踩过这个坑,最后统一换成了 SVG spinner,Safari、iOS WebView 都没问题。纯 CSS 的
border动画在 Safari 上就是个已知的性能黑洞,能躲就躲。