纯CSS无缝跑马灯关键在transform:translateX(-50%)+双份内容+flex对齐:单份用-100%必露白,因位移基准是自身宽而非容器宽;双份总宽≈200%,-50%位移使第二段无缝接替,需配合linear、overflow:hidden及独立transform声明。

纯 CSS 实现无缝滚动走马灯,关键不是“用不用 position”,而是避免用 position: relative/absolute 做位移——它触发重排、无法硬件加速、iOS 上卡顿明显。真正可靠的方案是 transform: translateX() + 双份内容 + flex 容器对齐。
为什么不用 left 或 top 做跑马灯
用 left / top 配合 @keyframes 看似简单,但实际会:
- 强制浏览器进行 layout(重排),滚动帧率常掉到 30fps 以下,尤其在低端 Android 或 iOS Safari 上肉眼可见卡顿
-
left: 100%是相对包含块宽度,而文本自身宽度可能远大于容器,导致动画时长失准、“滚太快”或“卡半截” - 无法利用合成层(compositing layer),
will-change: left无效,浏览器不会为其单独建图层
transform: translateX(-50%) 为什么比 translateX(-100%) 更稳
translateX(-100%) 指的是“移动自身宽度”,不是“填满容器”。单段文本滚动完直接跳回,中间必露白;而双份文本 + translateX(-50%) 才能视觉无缝:
- 两段文案并排总宽 ≈ 200%,位移 -50% 后,第二段刚好完全进入视口,第一段完全移出
- 动画终点不依赖文本真实宽度,只依赖容器逻辑宽度,响应式下不崩
- 必须显式写
animation-timing-function: linear,否则默认ease会让开头慢、中间快、结尾又慢,一眼就看出“一顿一顿” - HTML 中需手动复制内容,例如:
<div class="marquee">公告内容公告内容</div>
iOS Safari 上不动?检查 transform 声明拆分
iOS Safari 对复合 transform 解析严格,常见失效原因:
立即学习“前端免费学习笔记(深入)”;
- 把
transform: translateX(0) translateZ(0)写在同一行 → Safari 忽略translateZ(0),不触发合成层 - 正确写法是拆成两条独立声明:
transform: translateX(0); transform: translateZ(0); - 容器不能是
width: fit-content或靠内容撑开,必须有明确宽度(如width: 100%或固定值) - 加
will-change: transform仅在必要时用(比如高频滚动区域),滥用反而引发内存抖动
最易被忽略的点:动画时长不能拍脑袋定。文本越长,滚动一圈所需时间越长。若内容动态加载,得用 JS 读 scrollWidth 后再设 animation-duration,否则在小屏上“嗖”一下就没了。


















