直接用transform: translateX(-100%)会闪动,因单份内容动画结束时突跳回起点造成视觉断层;须用双份内容、容器宽200%、translateX(-50%)实现无缝衔接,并配合white-space:nowrap、overflow:hidden及硬件加速优化。

为什么直接用 transform: translateX(-100%) 会卡顿或闪一下
因为单份内容滚动完后,动画回到起点时内容突然跳回原位,视觉上就是“断层”。浏览器渲染时,@keyframes 到达 100% 后重置 transform,但原始文本已完全移出视口,空白区裸露一帧——尤其在高刷屏或大屏上特别明显。
这不是 CSS 写错了,而是动画逻辑没覆盖“衔接”这个环节。解决办法不是调速或加延迟,是让“下一段内容已在路上”。
- 必须复制内容:两份相同文本首尾紧贴,总宽度 ≥ 容器宽度 × 2
- 动画终点不能设为
-100%,而应设为-50%,这样第一份滚完时第二份刚好进画框 - 容器需设
overflow: hidden,且内部元素不能换行:white-space: nowrap
@keyframes 里写 translateX(-50%) 的真实含义
这里的 -50% 不是指“一半容器宽”,而是“父容器宽度的 50%”。它成立的前提是:内部文本容器(.marquee-content)宽度恰好为容器的 200% —— 即两份内容并排。
如果内容动态生成(比如 Vue/React 渲染),不能靠 JS 测宽再设动画时长,得用 CSS 原生可计算的方式。此时 % 单位才真正可靠;用 px 或 vw 都会错位。
- 错误示范:
transform: translateX(-1200px)→ 换设备就偏移失效 - 正确写法:
transform: translateX(-50%),配合双倍宽内容 - 动画时长建议用变量控制:
animation-duration: calc(1s * var(--speed, 20)),便于后期微调
如何让 hover 暂停不破坏循环节奏
CSS 的 animation-play-state: paused 本身没问题,但暂停后恢复时,动画会从当前帧继续——这会导致位移错乱,尤其当暂停点落在 47.3% 这种非整数帧时,重播可能跳一格。
真正稳定的暂停,是“冻结动画状态 + 保持 transform 值不变”,而不是依赖浏览器的帧调度。
- 给外层容器加 class:
.marquee.paused { animation-play-state: paused; } - 不要只对
.marquee-content加 hover,要作用于整个动画链路容器 - 若需点击跳转,记得在
pointer-events: none的遮罩层下放真实链接,避免 hover 区域被动画位移带偏
移动端 Safari 上跑马灯不动?检查这几个硬性条件
iOS 16+ 对 transform 动画有更严格的触发要求,单纯写 animation 可能被降级为软件渲染,甚至静止。
必须同时满足三项,否则 Safari 会拒绝启动硬件加速:
- 容器加
transform: translateZ(0)或will-change: transform - 动画属性只能是
transform和/或opacity,禁用left/top/margin -
.marquee-content不能有display: inline(会破坏 BFC,导致 width 计算异常),改用display: inline-block或flex
最容易被忽略的是最后一项:Safari 下 inline 元素在 white-space: nowrap 中的宽度行为和 Chrome 不一致,会导致 -50% 位移量实际生效值偏差 1–2px,循环即断裂。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











