必须写在html元素上,因浏览器滚动根容器是html而非body;body上无效,通配符不继承且易被覆盖;正确写法为html{scroll-behavior:smooth}。
直接在 html 元素上写 scroll-behavior: smooth; 就行,这是唯一可靠、零 JS、全局生效的方案。
html 上,而不是 body 或通配符?浏览器的滚动上下文根是视口(viewport),它绑定在 html 元素上,不是 body。写在 body 上完全无效——开发者工具里能看到 computed 样式里 scroll-behavior 仍是 auto。写 * { scroll-behavior: smooth; } 也不行,因为该属性不继承,且通配符优先级低,容易被重置样式覆盖。
常见错误现象:href="#contact" 点击后仍“瞬移”,检查 html 元素的 computed 样式,若不是 smooth,八成是写错位置或被 !important 覆盖。
html { scroll-behavior: smooth; }
@media 或 @supports 里(除非你明确要降级)html, body { scroll-behavior: auto !important; },需手动覆盖scroll-behavior: smooth 生效范围和边界条件它只对原生锚点跳转(<a href="#id">)、window.scrollTo()(未显式传 behavior 时)、element.scrollIntoView()(未传 behavior 时)起作用。不是“所有滚动都变平滑”,而是“所有由浏览器默认触发的滚动行为”被接管。
立即学习“前端免费学习笔记(深入)”;
容易被忽略的失效原因:
id 不存在,或拼写不一致(大小写敏感)display: none、visibility: hidden 隐藏,或父容器有 overflow: hidden 截断布局流scroll-behavior 不穿透边界,需在 shadow root 内单独设置prefers-reduced-motion: reduce),部分浏览器会自动禁用该效果html,改容器本身如果页面有自定义滚动区(比如聊天记录框、侧边菜单、SPA 路由容器),它的滚动行为不受 html 上的 scroll-behavior 影响。因为真正发生滚动的是那个 overflow-y: auto 的容器,不是整个视口。
例如一个聊天历史区域:
.chat-history { height: 400px; overflow-y: auto; scroll-behavior: smooth;}
关键点:
overflow-y: auto 或 scroll + 内容溢出scroll-behavior: smooth 就指望它可滚动;没有溢出,该属性无意义a 默认行为,scroll-behavior 失效,此时必须用 JS 调用 element.scrollIntoView({ behavior: 'smooth' })
启用 scroll-behavior: smooth 后,目标元素顶部常被 position: fixed 的导航栏盖住。最推荐的解法不是 JS 计算偏移,而是用 scroll-margin-top:
section { scroll-margin-top: 80px;}
这个值应等于固定头部高度。优势在于:
scrollIntoView 和原生锚点跳转都生效margin-top: -80px + padding-top: 80px 更干净,不破坏文档流真正难搞的从来不是怎么加平滑,而是确保滚动上下文存在、目标可见、偏移对齐——这些细节一漏,scroll-behavior: smooth 就只是个摆设。