scroll-behavior: smooth 必须写在 html 元素上才生效,写在 body 上无效;仅对锚点链接和 scrollIntoView()(需显式传 {behavior: 'smooth'})起作用,不适用于 scrollTop 或 scrollTo() 直接赋值;移动端需注意 Safari 版本兼容性及系统动效偏好。

scroll-behavior: smooth 必须写在 html 元素上才生效
绝大多数“加了没反应”的问题,根源就是样式写错了位置。浏览器的页面级滚动容器是 html 元素,不是 body。哪怕你写了 body { scroll-behavior: smooth; },在 Chrome、Firefox 中基本无效,Safari 更是直接忽略。
正确写法只有一行:
html { scroll-behavior: smooth; }
务必用开发者工具检查 html 元素的 computed 样式,确认 scroll-behavior 确实为 smooth,且未被 !important 覆盖(某些 UI 框架重置样式时会写 html, body { scroll-behavior: auto !important; })。
锚点跳转不平滑?先排查目标元素是否“可滚动定位”
scroll-behavior: smooth 只对两类行为起作用:用户点击 <a href="#section"></a> 这类锚点链接,以及 JS 调用 element.scrollIntoView()(且未传 behavior 参数时)。它不接管 element.scrollTop = 100 或 window.scrollTo(0, 200) 这类直接赋值操作。
立即学习“前端免费学习笔记(深入)”;
- 目标元素(如
<h2 id="section"></h2>)必须存在于 DOM 中,id值严格匹配(区分大小写、无空格、无前后空格) - 不能被
display: none或visibility: hidden隐藏;opacity: 0不影响,但元素仍需在文档流中 - 若用 Vue/React 动态渲染,确保锚点元素已挂载完成后再触发跳转,否则浏览器找不到目标
- 如果页面有 Shadow DOM,该属性不穿透边界,需在 shadow root 内单独设置
JS 调用 scrollIntoView() 仍硬跳?必须显式传参
即使 html 上设置了 scroll-behavior: smooth,调用 element.scrollIntoView() 时如果不带参数,浏览器仍按默认 { behavior: 'auto' } 执行,结果就是“啪”一下跳过去。
正确写法是:
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
注意:block 和 inline 值会影响对齐方式,block: 'nearest' 在部分浏览器中可能因无法精确计算偏移而降级为 instant。推荐明确指定 block: 'start' 或 block: 'center'。
另外,window.scrollTo() 完全不受 CSS 属性影响,必须写成:
window.scrollTo({ top: 0, behavior: 'smooth' });
移动端 Safari 和旧 WebView 中失效?别依赖 @supports 检测
iOS Safari 直到 15.4 才真正支持 scroll-behavior: smooth,15.0–15.3 版本静默忽略,所有 iOS 14 及更早版本完全不识别。安卓微信 X5 内核等 WebView 也有类似问题。
@supports (scroll-behavior: smooth) 只检测 CSS 属性是否被识别,不反映实际 JS 行为是否可用。更可靠的运行时判断是:
if (typeof Element.prototype.scrollIntoView === 'function') {
element.scrollIntoView({ behavior: 'smooth' });
} else {
// 降级方案,如 window.scrollTo()
}
还要注意系统偏好设置:prefers-reduced-motion: reduce 会静默禁用所有 behavior: 'smooth',哪怕代码里写了也无效——这是设计使然,不应绕过。


















