真正可用的无缝滚动必须用@keyframes+transform:translateX()手动实现,核心是双份内容并排、位移等于容器宽度、animation-timing-function:linear且三者实时对齐。

原生 和 ellipsize="marquee" 在现代移动端根本不可用——iOS Safari 已彻底忽略,Android WebView 行为不一致,且无法控制速度、暂停、方向,更不支持图文混排。真正可用的无缝滚动,必须用 @keyframes + transform: translateX() 手动实现。
为什么 translateX(-100%) 会露白、卡顿?
常见错误是只写 @keyframes { 0% { transform: translateX(100%); } 100% { transform: translateX(-100%); } },但这里的 -100% 指的是元素自身宽度,不是容器可视区宽度。当文本内容长度不能被容器宽度整除时,动画循环瞬间就会暴露空白间隙。
- 单段文本永远做不到视觉无缝——动画播完跳回起点,人眼必见“闪回”
-
-100%不等于“滚满一屏”,它只是“滚掉自己那么宽”,和容器无关 - 若文本过短,
-100%可能还没移出视口就结束了;过长则滚太快,末尾拖尾
必须复制内容 + 精确位移才能真无缝
核心是让两段相同内容并排,动画位移距离刚好等于容器宽度,这样第二段开头在第一段结尾处自然顶上。
- HTML 中至少重复一次内容:
文案文案 - CSS 中设
transform: translateX(-50%)(配合双份内容)或动态计算精确值,例如:总宽 800px、容器宽 200px → 位移应为-200px - 动画时长要匹配:想以 40px/s 匀速滚动,容器宽 200px → 一圈耗时
5s,设animation-duration: 5s - 务必加
white-space: nowrap,否则换行破坏宽度逻辑
linear 不是可选项,是硬性要求
默认 ease 会让动画起步慢、中间快、收尾又慢,跑马灯立刻显得“一顿一顿”,完全失去匀速滚动感。
- 错误写法:
animation: scroll 8s infinite;(隐式使用ease) - 正确写法:
animation: scroll 8s linear infinite;或显式声明animation-timing-function: linear - 即使
@keyframes只写了0%和100%,也必须靠linear控制播放节奏,不是靠关键帧插值
响应式与动态内容容易被忽略的坑
固定写死 animation-duration: 10s 在不同屏幕下必然失效;JS 注入内容后未重算宽度,滚动就会错位或卡半截。
- 容器宽度变化(如横竖屏切换)时,需用
ResizeObserver重新测scrollWidth并更新animation-duration - 用
will-change: transform提前提示浏览器走合成层,避免卡顿 - 移动端需加
overflow: hidden到父容器,否则 iOS Safari 可能触发弹性滚动干扰 - 悬停暂停用
:hover .marquee span { animation-play-state: paused; },但记得加touch-action: none防止 Safari 误触发长按菜单
最麻烦的从来不是写对那几行 @keyframes,而是宽度、位移、时长三者必须实时对齐——任意一个靠“估”,滚动就会断。动态内容尤其如此,别信“设个固定秒数就能跑通”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











