直接用animation: marquee 10s linear infinite会卡顿或跳帧,核心在于位移逻辑未对齐:translatex(-100%)终点未精确匹配内容宽度,导致视觉断点;必须使动画位移量等于单份内容总宽(非百分比),并采用双份镜像拼接结构确保无缝闭环。

为什么直接用 animation: marquee 10s linear infinite 会卡顿或跳帧
核心问题不在语法,而在位移逻辑本身:如果元素宽度固定、容器宽度也固定,transform: translateX() 从 0 到 -100% 后立刻跳回 0,浏览器渲染线程来不及抹除上一帧残留,人眼就会感知“闪”或“顿”。这不是 CSS bug,是动画断点没对齐。
- 必须让动画终点与起点在视觉上完全重合——即最后一帧的位移值,要等于第一个子项刚好完全移出视口的临界点
- 推荐用
translateX(-100%)+translateX(0)构成完整周期,但前提是整个滚动内容宽度 ≥ 容器宽度 × 2,否则无缝无法成立 - 避免用
left/right动画:触发重排,性能差;transform才走合成层
如何构造可复用的无限跑马灯 HTML 结构
关键不是写多少个 <span></span>,而是让 DOM 节点数和位移距离形成闭环。最稳方案是「双份内容镜像拼接」:
<div class="marquee">
<div class="marquee__inner">
<span>A</span><span>B</span><span>C</span>
<span>A</span><span>B</span><span>C</span>
</div>
</div>
-
.marquee设为overflow: hidden,宽高明确(不能是auto) -
.marquee__inner宽度设为内容总宽 × 2,且不换行:white-space: nowrap - 所有子项(如
<span></span>)需有固定宽度或内联盒模型一致,否则拼接处会露白 - 不要用 Flex 布局做
.marquee__inner:Flex item 的基线对齐或 gap 会破坏像素级无缝
@keyframes 中 translateX 的起止值怎么算才不跳
动画位移量必须严格等于单份内容的总宽度(含间隙),否则第二轮开始就错位。假设单份内容宽度为 W,那么:
- 起始帧:
transform: translateX(0) - 结束帧:
transform: translateX(-W)—— 注意不是-100%,因为%是相对父容器,而我们要的是相对自身宽度 - 所以必须用 JS 或预处理器先算出
W,再注入 CSS 变量;纯 CSS 方案只能靠100vw这类可靠单位估算
更稳妥的纯 CSS 写法(适用于等宽字符或图标):
@keyframes marquee {
0% { transform: translateX(100%); }
100% { transform: translateX(-100%); }
}
此时需确保 .marquee__inner 宽度 ≥ 200%(即两倍容器宽),否则内容不够铺满,末端会空白闪现。
移动端 iOS Safari 上动画突然暂停怎么办
iOS WebKit 对 transform 动画有节流策略:当页面切到后台或滚动快速发生时,animation 可能被暂停且不恢复。这不是 bug,是省电机制。
- 加
animation-play-state: running强制激活(但治标不治本) - 真正有效的是监听
visibilitychange事件,手动重置动画:el.style.animation = 'none'; setTimeout(() => el.style.animation = '', 10) - 更轻量的做法:用
will-change: transform提前声明,让浏览器保持图层活跃 - 别用
animation-delay做启动缓冲——iOS 下 delay 期间若页面不可见,delay 会累积,恢复后猛冲
无缝循环的本质是视觉欺骗,它依赖精确的尺寸关系和渲染节奏。一旦容器宽、字体渲染、缩放比例、设备像素比其中任一环变化,就得重新校准位移值——没有一劳永逸的 magic number。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











