如何用CSS和JavaScript实现稳定的无限循环SVG描边旋转加载组件
优化实现方案
原有实现问题根源
setInterval属于宏任务,浏览器标签页切换到后台时会被限制执行频率,恢复前台时会一次性执行堆积的回调,直接导致卡顿、转速异常飙升- 过渡动画用了
ease-in-out缓动曲线,本身就有启动加速、结束减速的过程,所以会有启动延迟 - 每次偏移量固定加800的逻辑没有和动画周期做对齐,也没有做数值重置,长期运行会出现数值溢出风险
最优方案:纯CSS原生动画实现(最稳定)
完全抛弃JS定时器,直接用CSS @keyframes 实现,由浏览器原生调度动画,后台标签页会自动暂停动画,恢复时不会有累积任务,转速完全均匀,启动无延迟。
代码示例
HTML
<svg id="loading" viewBox="0 0 240 240" fill="none" xmlns="http://www.w3.org/2000/svg"> <path id="icon" d="M42.3975 90C72.7709 37.3917 87.9576 11.0876 108.479 3.61845C121.734 -1.20615 136.266 -1.20615 149.521 3.61845C170.042 11.0876 185.229 37.3917 215.603 90C245.976 142.608 261.163 168.912 257.37 190.419C254.921 204.311 247.655 216.895 236.849 225.963C220.12 240 189.747 240 129 240C68.2532 240 37.8798 240 21.1507 225.963C10.3448 216.895 3.07901 204.311 0.629501 190.419C-3.16266 168.912 12.024 142.608 42.3975 90Z" /> </svg>
CSS
#loading { width: 100px; overflow: visible; position: absolute; z-index: 2; fill: transparent; stroke: #f1f1f1; stroke-width: 0.5rem; stroke-dasharray: 130px; stroke-dashoffset: 0; top: calc(50% - 50px); left: calc(50% - 50px); filter: drop-shadow(0px 3px 2px rgba(0, 0, 0, 0.6)); /* 新增动画配置:1s周期 线性运动 无限循环 */ animation: spin 1s linear infinite; } @keyframes spin { to { /* 刚好走完一个dasharray长度,实现无缝循环 */ stroke-dashoffset: 130px; } }
备选方案:JS 基于时间戳实现(如果需要动态控制动画)
如果确实需要用JS控制动画逻辑,就用requestAnimationFrame结合时间戳计算偏移量,避免定时器累积问题:
const loading = document.querySelector('#loading') const DURATION = 1000 // 动画周期1秒 const DASH_LENGTH = 130 // 描边间隔长度 let startTime = null function animate(timestamp) { if (!startTime) startTime = timestamp const elapsed = timestamp - startTime // 计算当前偏移量,取模避免数值无限增长 const offset = (elapsed / DURATION) * DASH_LENGTH % DASH_LENGTH loading.style.strokeDashoffset = offset requestAnimationFrame(animate) } requestAnimationFrame(animate)
该方案也不会出现标签页切换卡顿、转速飙升的问题,因为时间戳是实际流逝的时间,不会因为回调堆积出现跳变。
内容的提问来源于stack exchange,提问作者Lexizz
相关产品推荐
相关产品推荐

