抖动动画需用@keyframes定义对称的水平位移序列(如0%→25%→50%→75%→100%对应0→-4px→0→+4px→0),配合animation: shake 0.4s ease-in-out 2实现短促有力的失败反馈。

抖动动画用 @keyframes 定义最直接
抖动本质是水平方向快速往复位移,不需要旋转或缩放。用 @keyframes 显式定义 0% → 25% → 50% → 75% → 100% 的 translateX 偏移即可,比如从 0 → -6px → 0 → +6px → 0。关键点在于:中间帧必须对称,否则抖动会“偏一边”;位移量建议控制在 ±2px ~ ±8px,太大显得浮夸,太小看不出效果。
常见错误是只写两帧(0% { transform: translateX(0); } 100% { transform: translateX(-5px); }),这样只会单向晃一下,不是抖动。
示例定义:
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-4px); }
50% { transform: translateX(0); }
75% { transform: translateX(4px); }
}
animation 属性要配齐 duration、timing-function 和 iteration-count
只写 animation: shake; 不生效——CSS 动画必须至少指定时长和播放次数。抖动提示通常需要短促有力,推荐:
-
animation-duration: 0.4s;(太快看不清,太慢像卡顿) -
animation-timing-function: ease-in-out;(让起始和结束有加速度,比linear更“弹”) -
animation-iteration-count: 2;(1 次太轻,3 次以上干扰主操作) - 加上
animation-fill-mode: forwards;可选,但抖动是瞬态反馈,一般不保留最终状态
完整写法示例:
.input-error {
animation: shake 0.4s ease-in-out 2;
}
触发抖动不能只靠 class 切换,得确保重绘生效
给元素加 shake 类后没反应?大概率是浏览器跳过了重绘。常见原因:
- 类名添加前后,元素的
transform值没变化(比如之前已有transform: translateX(0),再加动画不会触发) - 动画被父级
overflow: hidden截断(抖动位移超出容器边界就看不见了) - 使用了
will-change: transform但未正确清理,导致合成层卡住
稳妥做法:触发前先强制重排,例如在 JS 中加一行 el.offsetLeft;,或改用 animation-name: none 重置后再设回 shake。更简单的方案是用 keyframe 名动态切换:
el.style.animation = 'none'; el.offsetHeight; // 强制重排 el.style.animation = 'shake 0.4s ease-in-out 2';
移动端要注意 transform 性能与 touch 响应延迟
在 iOS Safari 或部分安卓 WebView 中,单纯 translateX 抖动可能不够流畅,尤其列表项密集时。原因:未启用硬件加速,或主线程被 touch 事件阻塞。
优化方式:
- 加
transform: translateZ(0)或will-change: transform(仅在动画期间设置,用完即删) - 避免在
touchstart立即触发抖动——等touchend或校验失败后再播,防止误触连抖 - 慎用
animation-delay:输入校验后延迟 100ms 再抖,比立刻抖更符合用户预期
抖动不是炫技,它是失败信号。位移量、次数、时机稍一失控,就会让用户觉得页面“生病了”。真正难的不是写出来,而是让它刚好停在“警觉但不惊吓”的临界点上。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











