心跳动画核心是「快缩→慢放→短暂停」非线性节奏,分三段设为30%/50%/20%时长占比,配合transform-origin: center和硬件加速实现自然顿挫感。

用 @keyframes 实现心跳式缩放动画的核心逻辑
心跳动画本质不是匀速脉动,而是「快缩→慢放→短暂停→快缩」的非线性节奏。直接用 ease-in-out 模拟会显得呆板。真正接近生理呼吸/心跳的曲线需要分段控制时序和比例:
- 0% → 30%:快速缩小到约 85%(模拟心室收缩)
- 30% → 80%:缓慢放大至 105%(模拟舒张+轻微过冲)
- 80% → 100%:在 105% 处短暂停留 100ms,再回落到 100%(制造“顿挫感”)
关键不是总时长,而是这三段的时长占比——建议设为 30% / 50% / 20%,否则容易变成普通呼吸灯。
transform: scale() 必须搭配 transform-origin 才自然
默认以元素左上角为原点缩放,心跳跳动会偏移位置。所有真实场景都应显式设置中心锚点:
heart {
transform-origin: center center;
animation: heartbeat 1.2s infinite;
}
<p>@keyframes heartbeat {
0% { transform: scale(1); }
30% { transform: scale(0.85); }
80% { transform: scale(1.05); }
100% { transform: scale(1); }
}</p>
如果元素本身有 border-radius 或是圆形图标,transform-origin: center 就够用;但若容器内含文字或子元素,需确认父容器是否设置了 overflow: hidden,否则放大时内容可能溢出可见区域。
避免动画卡顿:必须启用硬件加速
CSS 动画在低端设备上容易掉帧,尤其叠加多个心跳元素时。scale() 本身不触发重排,但若同时修改 opacity 或 color,浏览器可能降级到软件渲染。强制开启 GPU 加速只需加一行:
heart {
transform: scale(1) translateZ(0);
/* 或更稳妥写法 */
will-change: transform;
}
注意:will-change 不要滥用——只加在真正需要动画的元素上,否则内存占用会上升;translateZ(0) 在 Safari 旧版本中更可靠,但现代 Chrome/Firefox 已基本无需。
和真实心率同步?别硬套 60bpm 的 1s 周期
临床静息心率是 60–100bpm,但 UI 中的“心跳”是心理暗示,不是医疗设备。实测用户感知最舒适的动画周期是 1.1s–1.4s,太快显得焦虑,太慢失去动感。如果真要对接 ECG 数据:
- 拿到实时 BPM 后,换算成
animation-duration: calc(60s / var(--bpm)) - 但必须限制范围:
min(1.4s, max(1.1s, calc(60s / var(--bpm)))) - 每次 BPM 变化时,用 JavaScript 动态更新
style.animationDuration,不要重写整个@keyframes
真正难的是让多个心跳元素(比如心电图波形里的不同点)保持相位差又不穿帮——这时得放弃纯 CSS,用 requestAnimationFrame 控制时间轴。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











