scroll-behavior: smooth 必须写在 html 元素上才生效,写在 body 或 * 上无效;验证需在 devtools 的 computed 面板检查 html 元素的 scroll-behavior 值是否为 smooth 且无 !important 覆盖。

scroll-behavior: smooth 必须写在 html 元素上才生效
写在 body 或通配符 * 上完全无效——浏览器的根滚动容器是 html 元素,不是 body。哪怕你在 DevTools 里看到内容“动”了,底层滚动层仍是 html。常见错误是 CSS 重置文件里有 html { scroll-behavior: auto !important; },直接覆盖掉你的设置。
验证是否生效:打开 DevTools → 选中 html 元素 → 在 Computed 面板搜索 scroll-behavior,确认值为 smooth 且无 !important 干扰。
- 正确写法:
html { scroll-behavior: smooth; }(建议放在全局样式最前面) - 不要同时写
html和body两个地方,旧版 Chrome 可能因优先级冲突降级为auto - 微前端或 CMS 可能注入 iframe,需用
document.documentElement确认当前根节点是否仍是html
锚点跳转不滚动?先查 href 和 id 是否严格匹配
这是最常被忽略的失效原因:不报错、不提示,只“不动”。HTML ID 是区分大小写的,且空格、中文、特殊符号都会导致失配。
-
href="#contact-us"必须对应<div id="contact-us">,不能是 <code>contactUs、contact_us或contact us(空格会被编码成%20) - ID 不要以数字开头(如
id="1section"),部分老 Safari 解析异常;推荐id="section-1" - 目标元素必须已挂载、可见:不能是
display: none、visibility: hidden,也不能在 Vue 的v-if或 React 的条件渲染中尚未渲染 - 同一页面内
id必须唯一;重复时浏览器只滚动到第一个匹配元素 - 给目标元素加样式:
#about { scroll-margin-top: 72px; }(值等于固定头部高度,含 border/padding) - 支持
px、rem、vh单位,但仅在目标处于可滚动上下文内才生效 - 避免用
margin-top: -72px+padding-top: 72px模拟偏移——这破坏文档流,且影响 JS 获取offsetTop - 若需动态适配(比如响应式头部高度变化),可用 CSS 自定义属性:
scroll-margin-top: var(--header-height, 72px); - 正确调用:
el.scrollIntoView({ behavior: 'smooth', block: 'start' }); - 必须判空:
if (el && el.offsetParent) { ... }——offsetParent === null表示元素被隐藏、未挂载,或父级有pointer-events: none -
block推荐'center'更安全(避开固定头部),或配合scroll-margin-top用'start' - 系统开启「减少运动」偏好时,所有
behavior: 'smooth'会被浏览器强制禁用,这是预期行为,不可绕过
固定头部遮挡内容?优先用 scroll-margin-top 补偿
点击锚点后内容顶部被导航栏盖住,不是 JS 没算 offset,而是浏览器默认把目标元素顶到视口最上方。用 scroll-margin-top 是标准、轻量、CSS 原生的解法。
JavaScript 手动滚动必须显式传 { behavior: 'smooth' }
scrollIntoView() 和 window.scrollTo() 默认都是瞬跳,漏掉 behavior 参数就白写了。尤其注意 SPA 场景下,a 标签常被路由拦截,scroll-behavior: smooth 不会自动触发。
scroll-behavior 不会创造滚动能力,它只修饰已有滚动行为。如果页面内容高度不足一屏,或局部容器没有 overflow: auto,加了也白加。











