心跳动画需用非对称@keyframes模拟“快缩→慢放→短暂停”:0% scale(1),30% scale(0.95),70% scale(1.08),100% scale(1);配合animation-play-state控制触发、animationend移除类实现单次脉冲。

用 @keyframes 定义心跳缩放曲线
纯 CSS 实现心跳动画,核心是模拟真实心跳的「快缩→慢放→短暂停」节奏,不能简单用 scale(1.2) 往返。真实心跳收缩快、舒张慢,所以动画关键帧要非对称:前 30% 时间快速缩小(scale(0.95)),后 70% 缓慢放大回 1 并略超调(scale(1.08)),再回落到 1。
- 推荐写法:
@keyframes heartbeat { 0% { transform: scale(1); } 30% { transform: scale(0.95); } 70% { transform: scale(1.08); } 100% { transform: scale(1); } } - 别用
ease-in-out—— 它对称,无法表现收缩快、舒张慢的生理特征 - 动画时长建议设为
1.2s~1.5s,太短像抖动,太长失去提醒感
给元素添加动画并控制触发时机
动画本身要可中断、可重复触发,尤其用于提醒场景(比如新消息红点)。直接写 animation: heartbeat 1.4s 会导致连续点击时动画重叠或卡顿。
- 用
animation-name+animation-duration分开写,方便 JS 动态添加/移除类名 - 加
animation-fill-mode: forwards防止动画结束后跳回初始状态 - 关键:用
animation-play-state: paused初始暂停,JS 触发时才play,避免页面加载就自动播 - 示例类名:
.pulse-trigger { animation: heartbeat 1.4s; animation-fill-mode: forwards; animation-play-state: paused; } .pulse-trigger.active { animation-play-state: running; }
避免布局抖动和性能问题
transform: scale() 本身是 GPU 加速的,但若父容器有 overflow: hidden 或元素带边框/阴影,缩放时可能触发重排或模糊。
- 确保动画元素是独立图层:加
will-change: transform或transform: translateZ(0) - 别在
width/height上做动画 —— 这会强制 Layout,卡顿明显 - 如果元素含文字,缩放可能导致字体渲染变糊,可加
-webkit-font-smoothing: subpixel-antialiased缓解 - 移动端注意:iOS Safari 对
scale小数精度敏感,scale(0.949)可能被四舍五入成0.95,导致节奏失真,统一用两位小数即可
配合 JS 实现「单次脉冲」而非循环播放
提醒类动画通常只需播一次,比如用户收到新通知时闪一下。CSS 默认 infinite 会不停循环,必须干预。
立即学习“前端免费学习笔记(深入)”;
- 不要设
animation-iteration-count: 1—— 它播完会回退到初始态,视觉上像“抽搐” - 正确做法:JS 添加类后,监听
animationend事件,立刻移除类名el.addEventListener('animationend', () => { el.classList.remove('active'); }, { once: true }); - 如果需支持手动取消(比如用户已查看),加个
clearTimeout或用el.getAnimations().forEach(a => a.cancel())
@keyframes 不够,不处理 animationend 和 play-state,很容易变成“播不停”或“播一半卡住”。


















