svg loading 图标使用 animation 抖动解决方案
最近发现了一个 loading 动画的抖动现象,如下图所示,可以明显看到鼠标移到按钮上后,loading动画没有沿着中心点旋转
动画采用了标准的animation方案,图标是用的 svg。
.ts-button-spinner {
transform-origin: center center;
animation: ts-button-spin 1s infinite linear;
}
@keyframes ts-button-spin {
from {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
排查过程
第一想法是在项目里面建一个空页面测试,结果发现是正常的,那说明可能是由项目的其他代码影响了,只能在原抖动的页面去一个一个排除,看是哪个代码影响了,最终发现竟然是由引入的第三方 sortablejs 库引起的。
import Sortable from "sortablejs"
发现 sortablejs 引入页面,即使不去使用它也会触发抖动,那说明这个库一定是做了全局初始化之类的动作,我第一直觉是去去调试工具看下这个svg元素的事件绑定,结果真的发现 sortablejs 有给 document 绑定事件。
于是在它的源码中挨着查找,定位到这个绑定事件的代码。
去掉这段代码loading就不会抖动了,给document绑定一个事件就会导致动画抖动也是非常奇怪,仔细再探究是哪个点影响了,发现是这个绑定事件的配置。
于是我在页面去掉 sortablejs 的引入,自己写一个document的事件绑定来验证,结果发现真的也能导致动画出现抖动。
document.addEventListener('touchmove',()=>{},{
passive:false,
capture:false
})
再接着排查是那个参数导致的,最终发现只有 passive 设为false 时会触发动画的抖动。
由于整个文件在Vue工程中,为了排除其它因素,将上述动画放到一个html文件中来验证。
<body>
<style>
.ts-button-spinner {
user-select: none;
transform-origin: center center;
animation: ts-button-spin 1s infinite linear;
}
@keyframes ts-button-spin {
from {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
button{
display: inline-flex;
align-items: center;
color: #000;
width: 200px;
font-size: 32px;
}
</style>
<div>
<button>
<svg
viewBox="0 0 48 48"
draggable="false"
xmlns="http://www.w3.org/2000/svg"
class="ts-button-spinner "
width="1em"
height="1em"
>
<path
d="M24 4a20 20 0 1 1-20 20"
stroke-width="3"
fill="none"
stroke="currentColor"
stroke-linecap="round"
>
</path>
</svg>
按钮
</button>
</div>
<script>
document.addEventListener("touchmove", () => {}, {
passive: false,
capture: true,
})
</script>
</body>
放到html中,基本上排除了其它因素的影响。测试发现鼠标移到按钮上很容易就触发抖动,说明这个问题可能真的是存在的。
那么如何解决这个问题呢?只能接着继续在这个html排查,发现将button换成div就不会出现抖动,如果不想将button换成div,经过测试将动画换成 svg 的 animateTransform 也不会触发抖动。
<svg
viewBox="0 0 48 48"
draggable="false"
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
>
<path
d="M24 4a20 20 0 1 1-20 20"
stroke-width="3"
fill="none"
stroke="currentColor"
stroke-linecap="round"
>
<animateTransform
attributeName="transform"
type="rotate"
from="0 24 24"
to="360 24 24"
dur="1s"
repeatCount="indefinite"
/>
</path>
</svg>
以上是这个CSS动画抖动的排查过程,前端开发经常会碰到类似问题,有很多问题大概率是不能直接搜索到答案的,只能自己去一步一步排查,排查的过程要学会利用方法,特别是影响因素非常多的时候,要学会用排除法,只有找到问题的根源,才能对症下药。
上述问题目前也没找到真正的原因,目前也只是找到了2个解决方案,后续还会继续探究。