心跳动画必须用 transform: scale(),不可单独写 scale();应模拟“快缩慢回”节奏,使用 cubic-bezier(0.6, 0, 0.4, 1);颜色明度变化优先用 hsl() 调 l 值;@keyframes 中 0% 和 100% 必须显式声明且严格一致;推荐时长 1.2s~1.6s;启停应结合 focus-within、pointerdown 与自动暂停,避免重置动画状态。

心跳动画用 transform: scale() 还是 scale()?
直接用 transform: scale(1.05),别写成 scale(1.05) —— 后者不是合法 CSS 值,浏览器会静默忽略。缩放必须挂在 transform 属性下,这是最常被复制粘贴错的地方。
真实场景里,心跳不是匀速放大再缩小,得模拟心肌收缩的“快缩慢回”:前 30% 时间完成 90% 的缩放变化,后 70% 缓缓回弹。用 cubic-bezier(0.6, 0, 0.4, 1) 比 ease-in-out 更接近生理节奏。
- 别用
animation-timing-function: ease,它会让缩放头重脚轻,像气球漏气 - 起始状态建议设为
transform: scale(1),避免首次渲染闪动 - 如果元素有 border 或阴影,缩放时可能模糊——加
will-change: transform提前提示渲染层
颜色明度变化该用 hsl() 还是 rgba()?
用 hsl()。明度(l)可单独调节,不干扰色相和饱和度,改一个数值就能实现“呼吸感”;而调 rgba() 的 alpha 会同时影响背景穿透和文字可读性,在深色模式下极易翻车。
典型错误是写成 hsl(350, 80%, 60%) → hsl(350, 80%, 75%),看似明度升高,但人眼对红色系明度变化极不敏感——换到橙红过渡(比如 hsl(15, 90%, 60%) → hsl(15, 90%, 72%))效果立竿见影。
立即学习“前端免费学习笔记(深入)”;
- 避免在动画中切换色相(
h),会导致视觉跳变,专注调l - 若需兼容 IE,
hsl()安全,但 IE 不支持will-change和部分贝塞尔曲线 - 移动端 Safari 对
hsl()动画性能友好,比反复改rgb()十六进制值更稳
@keyframes 里要不要写 0% 和 100%?
要写,而且必须显式写出。省略 0% 会导致动画首帧从元素当前 transform 和 color 状态开始,而不是你预期的“静息态”,尤其当元素已带内联样式或 JS 修改过状态时,心跳一触发就抽搐。
更关键的是:心跳是循环动作,100% 必须严格等于 0%,否则每轮结束会有微小偏移,叠加几次后缩放失真、颜色漂移。这不是理论风险,是真实发生过的 UI 漂移 bug。
- 示例写法:
@keyframes heartbeat { 0% { transform: scale(1); color: hsl(15, 90%, 60%); } 30% { transform: scale(1.08); color: hsl(15, 90%, 72%); } 100% { transform: scale(1); color: hsl(15, 90%, 60%); } } - 别用
from/to替代0%/100%,部分旧版 Android WebView 解析不准 - 动画时长建议设为
1.2s~1.6s,接近成人静息心率,太快像抽搐,太慢失去反馈感
如何让心跳动画只在用户“注视”时运行?
靠 :hover 太粗糙,手机没 hover;靠 IntersectionObserver 监听进入视口又太重。真正轻量的解法是监听 focus-within + pointerdown 组合,再加一个 3 秒自动暂停计时器。
核心逻辑:用户点按或聚焦到该 UI 区域时启动动画,3 秒无交互则暂停。既省电,又避免后台标签页里动画狂转拖慢性能。
- CSS 里用
.heartbeat-trigger:focus-within .heartbeat-anim { animation-play-state: running; } - JS 中绑定
pointerdown后立即setTimeout(() => el.style.animationPlayState = 'paused', 3000) - 千万别用
visibility: hidden或display: none控制动画启停——会重置动画状态,再显示时从头开始
复杂点在于:多个心跳元素共存时,每个都要独立计时;容易被忽略的是,键盘 Tab 焦点切换也得触发,否则无障碍访问失效。










