绝对定位跑马灯卡顿的根源在于left动画触发重排且重置突变,唯一可靠解法是双轨道错峰滚动:两组相同DOM并行动画,分别设20s动画和-10s延迟,配合overflow:hidden与严格尺寸控制。

直接用 position: absolute 做跑马灯,90% 的概率会卡顿、跳帧或在 Safari 上完全不动——问题不在动画写法,而在单组元素位移后重置 left 值破坏了时间连续性。
为什么 absolute + left 动画容易闪跳
浏览器对 left 的修改会触发 layout(重排),尤其当文本撑宽不固定时,每帧计算都可能抖动;更关键的是,动画播完必须靠 CSS 自动“跳回”起点,这个突变无法被平滑插值,视觉上就是一帧空白或错位。iOS Safari 对负 animation-delay 的支持也不稳定,进一步放大问题。
双轨道错峰滚动是唯一可靠解法
必须用两组完全相同的 DOM 节点并行滚动,靠负延迟错开起始时机,让一份刚出视口时另一份刚好顶上。这不是“优化技巧”,而是视觉无缝的必要前提。
- 两组子元素都要加
position: absolute,且父容器设overflow: hidden和严格匹配单个轨道高度/宽度 - 动画定义为
@keyframes marquee-loop { 0% { left: 100%; } 100% { left: -100%; } }—— 这比left: 0 → left: -100%更安全,避免依赖父宽计算误差 - 第一组用
animation: marquee-loop 20s linear infinite,第二组加animation-delay: -10s - 别把
transform: translateX()和left混用在同一元素上,Safari 会忽略后者
动态内容加载时最易忽略的坑
DOM 渲染完成前就加动画类,Safari 可能直接跳过首帧,导致初始位置偏移。必须等 offsetWidth 可读后再启用动画:
立即学习“前端免费学习笔记(深入)”;
const content = document.querySelector('.marquee-content');
content.addEventListener('load', () => {
content.classList.add('animate');
});
// 或用 requestAnimationFrame 确保渲染后执行
如果内容由 Vue/React 动态注入,不能只靠 v-if 或 useEffect 触发类名切换,得监听 offsetWidth 变化或用 ResizeObserver。
真正难的不是写出动画,而是让两段内容在任意屏幕尺寸、任意文本长度下,始终严丝合缝地交接——这要求容器宽高、字体大小、行高全部锁定,且任何 CSS 继承或重置都不能破坏 white-space: nowrap 和 overflow: hidden 的组合效果。


















