根本原因是浏览器移动端默认不为非合成层元素开启硬件加速,导致滚动被迫走主线程重排重绘;需用translate3d(0,0,0)+will-change动态控制GPU加速,并避免border-radius等降级属性。
为什么
或
在移动端滚动会卡顿
根本原因不是“动画太复杂”,而是
浏览器
在移动端默认不为非合成层元素开启硬件加速,导致滚动文字被迫走主线程重排重绘。尤其当父容器有
、文字含阴影或使用了
等渲染增强时,帧率极易跌破 30fps。
常见错误现象包括:文字突然跳帧、滚动速度不匀速、快速滑动页面时文字直接暂停。
安卓
WebView(尤其旧版)对
支持不稳定,盲目加反而引发闪烁
iOS Safari 对
的触发更敏感,但需确保元素不被其他 CSS(如
)降级回软件渲染
文字内容动态更新(如实时新闻跑马灯)时,频繁 DOM 操作会阻塞合成器线程
用
+
正确触发 GPU 加速
关键不是“加了就行”,而是加在对的时机、对的元素、配合对的清理逻辑。
推荐写法(以水平滚动为例):
立即学习
“
前端免费学习笔记(深入)
”;
比
更可靠,避免 iOS 15.4+ 的部分兼容问题
建议只在动画开始前通过 JS 动态添加,动画结束后立即移除,否则长期占用 GPU 内存
禁止在该元素上设置
、
或
,这些会强制合成层回退
用
替代 CSS 动画控制滚动节奏
CSS 动画在低端 Android 设备上容易因时间函数抖动导致卡顿;而 JS 驱动可主动丢帧保节奏,更适合动态内容。
Comet AI 浏览器
下载 Comet AI 浏览器,体验由 Perplexity AI 驱动的革命性上网方式。内置 AI 助手可实时总结网页、跨标签页对比信息、自动执行任务。告别繁琐操作,让 AI 成为你的浏览副驾,大幅提升研究与工作效率。支持 Windows、macOS、Android 和 iOS。
下载
实操要点:
用
获取当前偏移,而非依赖
(后者触发同步布局计算)
每帧只做一次
,避免读写交替
当页面进入后台(
)或滚动区域不可见时,必须调用
,否则持续消耗电量
示例节选:
字体与文字渲染本身就在拖慢帧率
很多人忽略:文字重绘是移动端合成层最重的操作之一。系统字体(如
,
)比自定义 Web Font 渲染快 2–3 倍,且抗锯齿策略更轻量。
禁用
—— 它会让文字变细但显著增加光栅化耗时
避免
,哪怕只是
,也会让浏览器放弃亚像素渲染,改用整像素模糊
单行滚动文字建议用
+
,而不是靠 flex 或 grid 布局撑开,后者易触发不必要的 relayout
真正卡顿的根源,往往藏在你认为“无关紧要”的字体设置和动画外层容器的 overflow 规则里。别急着换库,先检查
是否真为
,再看 DevTools 的 Rendering 面板里有没有“Paint flashing”高频闪烁。
marqueetransform: translateX()overflow: hiddenfont-smoothwill-change: transformtransform: translate3d(0, 0, 0)filtertransform: translate3d()will-change.scroll-text {
transform: translate3d(0, 0, 0);
will-change: transform;
/* 必须移除可能触发重排的属性,如 width: fit-content */
}
@keyframes scroll-move {
from { transform: translate3d(100%, 0, 0); }
to { transform: translate3d(-100%, 0, 0); }
}translate3d(0, 0, 0)translateZ(0)will-change: transformborder-radiusbox-shadowbackground: linear-gradient()requestAnimationFramegetBoundingClientRect()offsetLeftelement.style.transform = `translate3d(${x}px, 0, 0)`visibilitychangecancelAnimationFramefunction animateScroll() {
if (!isInViewport(el)) return;
x -= speed;
el.style.transform = `translate3d(${x}px, 0, 0)`;
if (x < -el.scrollWidth) x = el.parentElement.clientWidth;
rafId = requestAnimationFrame(animateScroll);
}-apple-systemsystem-ui-webkit-font-smoothing: antialiasedtext-shadow0 0 1pxwhite-space: nowrapoverflow: hiddengetComputedStyle(el).willChangetransform