原生标签已废弃,现代项目须用css动画或javascript实现;css方案用@keyframes+translatex配合内容复制实现无缝匀速滚动,js方案用requestanimationframe+scrollleft支持暂停、加速等交互,二者均需处理dom加载时机、移动端适配与ssr一致性。

原生 <marquee></marquee> 标签已废弃,现代项目中必须用 CSS 动画或 JavaScript 实现,否则会在 Chrome/Firefox 中失效、不兼容无障碍访问、且无法精确控制滚动节奏。
用 CSS @keyframes 实现单行文字匀速滚动
这是最轻量、最可控的方式,适合 banner 提示、新闻滚动条等场景。关键不是“动起来”,而是让首尾衔接自然、不闪跳。
- 把文字内容复制一遍拼接(如
"最新公告:系统维护中 → 最新公告:系统维护中 →"),避免动画结束时回跳 - 用
animation: scroll 15s linear infinite控制总时长,数值越小滚动越快 - 必须设容器
overflow: hidden,否则滚动出界会撑开布局 - 注意字体抗锯齿和 subpixel rendering:Chrome 下若出现模糊抖动,加
transform: translateZ(0)强制 GPU 加速
div.marquee {
white-space: nowrap;
overflow: hidden;
}
div.marquee span {
display: inline-block;
animation: scroll 20s linear infinite;
}
@keyframes scroll {
0% { transform: translateX(100%); }
100% { transform: translateX(-100%); }
}
用 scrollLeft + requestAnimationFrame 做精准可控滚动
当需要暂停/加速/点击跳转、或滚动内容含图片/链接时,CSS 方案会力不从心。JS 方案能监听用户交互、动态调整速度、兼容 IE11(需 polyfill)。
- 不要用
setInterval—— 它不与屏幕刷新率同步,易卡顿;必须用requestAnimationFrame - 每次帧更新只改
element.scrollLeft,比操作transform更稳定(尤其在低配安卓 WebView 中) - 检测滚动到底部后,立即重置
scrollLeft = 0并取消动画帧,再重新启动,避免视觉断层 - 鼠标悬停暂停需同时监听
mouseenter/mouseleave,并在离开时恢复上一帧的起始偏移量,否则会跳帧
遇到 Uncaught TypeError: Cannot read property 'scrollWidth' of null 怎么办
这个错误几乎都发生在 DOM 元素还没挂载就执行 JS 滚动逻辑,比如 Vue 的 mounted 钩子里没等子元素渲染完,或 React 的 useEffect 里没加 ref 判空。
- 确保获取元素用
document.querySelector或ref后,先判断是否为null - 滚动逻辑放在
setTimeout(() => {}, 0)或queueMicrotask中,让浏览器完成一次 DOM 渲染后再读取scrollWidth - 如果内容是异步加载(如 API 返回文案),必须在数据到达并渲染完毕后再初始化滚动,不能写死在组件初始化阶段
真正难的不是让字动起来,而是滚动节奏和内容长度匹配、移动端 touch 操作不冲突、以及在 SSR 场景下避免 hydration mismatch —— 这些细节不处理,上线后就会在特定机型或网络条件下突然卡住或错位。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











