震动动画必须用@keyframes定义多帧位移序列,通过js点击时添加类触发,动画结束后监听animationend移除类,仅在真实错误时使用并配合按钮禁用。

震动动画要用 @keyframes 定义,不能靠 transition 或 transform 单次位移
纯 CSS 实现点击震动,本质是让按钮在短时间内快速左右偏移,形成视觉抖动。这必须用 @keyframes 声明一串位移帧,再通过 animation 触发。直接写 transform: translateX(5px) 不会动,加 transition 也无效——震动不是平滑过渡,而是多段突变。
常见错误是试图用 :active + transform 模拟震动,结果只闪一下或完全没反应。正确做法是:定义动画、绑定到类(比如 .shake),JS 点击时加类、动画结束后移除。
-
@keyframes shake建议至少 6 帧,从 0 → +10px → -10px → +8px → -8px → 0,避免对称导致“卡顿感” - 动画时长控制在
0.4s内,过长像晃手机,过短看不出效果 - 必须设
animation-fill-mode: forwards吗?不用——震动是瞬态反馈,播完就该回原位,所以用backwards或默认值即可
给按钮加震动要靠 JS 控制 class,CSS 本身无法监听 click
CSS 没有 :clicked 伪类,:active 只在鼠标按下瞬间生效(约 200ms),根本撑不起完整震动周期。所以必须用 JS 在点击时添加一个类,让动画跑起来。
容易忽略的点:动画播完后不清理 class,下次点击可能被 animation-play-state: paused 卡住,或触发浏览器跳帧。稳妥做法是用 animationend 事件监听并移除。
- 给按钮加
id="submit-btn"或class="error-btn",方便 JS 绑定 - JS 中用
element.classList.add('shake'),别用className = 'shake'(会覆盖原有 class) - 监听
animationend时,检查event.animationName === 'shake',避免误删其他动画 - 移动端要注意
click有 300ms 延迟,建议用touchstart替代(但需防重复触发)
animation-timing-function 别用 ease,选 steps(1, end) 或 linear
震动要的是“顿挫感”,不是缓入缓出。用 ease 会让前后几帧变化太慢,中间又太快,看起来像晃了一下就软塌下去;用 linear 虽然均匀,但缺乏冲击力。
更优解是用 steps(1, end) 配合关键帧里的离散位移(比如每帧都设 transform: translateX(...)),能模拟出类似老式机械按键的“咔哒”节奏。不过兼容性稍弱(IE 不支持 steps),生产环境可降级为 linear。
- 完整 animation 声明示例:
animation: shake 0.38s linear both -
both表示动画前后都应用from和to的样式,这里其实不需要,删掉更干净 - 如果按钮本身有
transform: scale(0.95)这类变形,震动动画里务必显式重置,否则会叠加导致位移异常
真出错时才震动,别滥用 —— 错误状态得由业务逻辑判断
震动是负面反馈,意味着操作失败(如表单校验不通过、接口返回 400)。不是所有按钮点击都要震,也不是每次点击都该震。很多人把震动当“酷炫动效”加在提交按钮上,结果用户成功提交后也被震一下,体验混乱。
关键点在于:震动时机必须和真实错误状态同步。JS 里不能在 onclick 里无脑加 shake,而要在 fetch 失败、校验函数返回 false 后再触发。
- 表单场景下,先调
checkForm(),仅当返回false时执行震动逻辑 - API 调用后,只在
response.status >= 400或data.success === false时震动 - 震动期间最好禁用按钮(
button.disabled = true),防止连续猛点导致动画队列堆积 - 同一按钮 1 秒内重复错误,可加节流,避免高频震动引发不适
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











