animation-iteration-count: infinite 是唯一可靠、零 js 的 css 循环方案,漏写或写错将导致动画仅播放一次;必须显式声明,因默认值为 1;@keyframes 名称须严格匹配且前置定义;infinite 下 animationend 永不触发;滚动触发动画需用 intersectionobserver 控制 animation-play-state。

animation-iteration-count: infinite 是唯一可靠、零 JS 的 CSS 循环方案,漏写它或写错位置,动画就只播一次。
animation-iteration-count 必须显式声明,不能靠默认值
浏览器对 animation 简写属性的解析是“有则覆盖,无则用默认”——而 animation-iteration-count 的默认值是 1,不是 infinite。哪怕你写了 animation: spin 2s linear,只要没带上 infinite,动画播完就停。
常见错误写法:
-
animation: spin 2s linear;→ 缺infinite,只播一次 -
animation: spin 2s linear 0;→0是无效值,退回到默认1 -
animation: spin 2s linear -1;→ 同样无效,不循环
正确写法(任选其一):
animation: spin 2s linear infinite;animation-name: spin; animation-duration: 2s; animation-timing-function: linear; animation-iteration-count: infinite;
@keyframes 名称拼错或未定义,动画根本不会启动
@keyframes 声明和 animation-name 必须完全一致(大小写敏感),且必须在引用前定义。CSS 不报错,但动画静默失效。
典型问题:
- HTML 中写
class="rotate",CSS 却定义了@keyframes rotation { ... },但.rotate里写的是animation-name: rotate;→ 名称不匹配 -
@keyframes spin { ... }写在.spinner规则之后,而该规则又用了animation: spin ...→ 部分浏览器(尤其旧版 Safari)可能忽略 - 在
@keyframes中用了transform: none→ 它不会清除已有 transform,应写成transform: translateX(0) rotate(0)
验证技巧:临时把 animation-iteration-count 改成 2,看是否播两次;如果一次都不播,大概率是 keyframes 名称或作用域问题。
无限循环下 animationend 事件永远不会触发
很多人想监听每次循环结束做点事(比如切换文案、更新计数器),但只要 animation-iteration-count: infinite 生效,animationend 就彻底失联——因为“结束”不存在。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
替代方案只有两个靠谱路径:
- 用
setInterval模拟周期回调:时间间隔严格等于动画时长(如动画3s,就setInterval(fn, 3000)),但注意页面失焦时定时器会漂移 - 改用
requestAnimationFrame+ 时间戳手动驱动:完全接管帧逻辑,适合需要响应拖拽、暂停、变速等交互的场景
别写这种无效代码:el.addEventListener('animationend', () => el.classList.remove('looping').classList.add('looping')) —— 它既不会触发,也起不到重播作用。
滚动触发动画 + 循环,得用 IntersectionObserver 控制开关
如果元素在视口外就提前开始循环动画,不仅浪费性能,还可能造成视觉混乱(比如用户还没看到,加载图标已转了十圈)。
正确做法是:初始状态禁用动画(animation-play-state: paused),进入视口时设为 running,离开时再暂停。
示例逻辑:
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const el = entry.target;
if (entry.isIntersecting) {
el.style.animationPlayState = 'running';
} else {
el.style.animationPlayState = 'paused';
}
});
}, { threshold: 0.1 });
observer.observe(document.querySelector('.marquee'));
注意:不要用 visibility: hidden 或 display: none 切换,它们会中断动画状态;animation-play-state 是唯一可逆、不影响渲染流的控制方式。
真正容易被忽略的是衔接问题:当动画首帧和末帧状态不一致(比如 opacity: 1 → opacity: 0),infinite 循环会明显闪一下。要么让两帧自然过渡,要么加 animation-direction: alternate 配合调整关键帧顺序。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










