长按触发环形加载动画需javascript判断按压时长(≥300ms)添加is-loading类,css用伪元素+clip-path+rotate(720deg)实现顺时针匀速旋转,animation-fill-mode:forwards保持终态,touchstart/touchend兼容移动端,animationend清理类。

按钮长按时触发环形加载动画,不能只靠 :active
因为 :active 是瞬时状态——手指按下就触发、抬起就消失,撑不起一个持续 1.5 秒的环形加载动画。真要“长按才动”,得用 JavaScript 监听 mousedown + setTimeout 控制动画启停,CSS 只负责定义动画本身。
常见错误现象::active 里加 @keyframes 动画,结果一松手就中断,或者根本没机会播完;更糟的是在移动端,:active 响应延迟甚至不触发。
- 必须用 JS 判断按压时长(比如 ≥ 300ms)再添加加载类,如
is-loading - CSS 动画需设为
animation-fill-mode: forwards,保证最后一帧停留 - 移动端还要监听
touchstart/touchend,不能只靠鼠标事件
用 ::after 伪元素画环形,比改 border 更可控
直接 animating border 的 width/color 会牵扯布局、且无法实现“从 0° 开始顺时针描边”的效果;而用伪元素 + border-radius: 50% + clip-path 或 transform: rotate() 组合,才是可靠路径。
性能影响:用 transform 和 opacity 触发 GPU 加速,避免 animating width 或 height 引起重排。
立即学习“前端免费学习笔记(深入)”;
- 推荐方案:伪元素设为圆形,用
clip-path: inset(0 0 0 50%)切一半,再配合rotate()模拟“画弧” - 兼容性注意:
clip-path在 Safari 旧版本需-webkit-clip-path - 别用
border-image或 SVG<circle></circle>内联,增加 DOM 复杂度,维护成本高
.btn.is-loading::after {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 16px;
height: 16px;
margin: -8px 0 0 -8px;
border: 2px solid #ccc;
border-radius: 50%;
border-top-color: transparent;
animation: spin 1s linear infinite;
}
环形动画的关键帧必须绕开 transform: rotate(360deg) 的插值陷阱
CSS 对 rotate(0deg) → rotate(360deg) 默认做最短路径插值,结果可能不动或倒转——尤其当动画循环多次时,视觉上会“跳帧”或“卡顿”。真实环形加载要求稳定顺时针匀速转。
解决办法只有一个:把终点设成 rotate(720deg) 或更高,强制走满整圈。
- 错误写法:
to { transform: rotate(360deg); }→ 浏览器可能优化成 0deg - 正确写法:
to { transform: rotate(720deg); },或分三段:0deg → 360deg → 720deg - 别依赖
animation-timing-function: steps(),它不适合旋转动画
长按中途取消时,动画必须可逆或立即收尾
用户按住 200ms 后松手,此时动画还没启动;但如果已启动(比如 400ms 后),松手时不能让环停在半路——得要么立即消失,要么补完最后一圈再收。
最容易被忽略的点:JS 里清除定时器只是防止动画开始,但若动画已在运行,class 还在,就得手动移除 class 并重置伪元素状态。
- 给按钮加
transition: opacity .15s,移除is-loading时带淡出 - 动画结束回调用
animationend事件清理 class,避免残留 - 别在
touchend里直接el.classList.remove("is-loading")就完事——得先判断动画是否已触发










