scroll-behavior: smooth 必须写在 html 元素上才生效,写在 body 或局部容器无效;仅对原生锚点跳转和 scrollIntoView() 生效,需配合 scroll-margin-top 避开固定头部,并受 iOS Safari 版本及系统“减少动画”偏好限制。

scroll-behavior: smooth 必须写在 html 上才生效
加了但没反应,90% 是因为写错了作用对象。浏览器真正的滚动容器是 html 元素,不是 body,也不是某个 div。写在 body 上在 Safari 和部分旧 Chrome 中完全无效;写在局部容器(如 .content)上,只影响那个容器内部滚动,对全局锚点跳转没用。
正确写法只有一行,且不能嵌套、不能加 !important、不能放在媒体查询里:
html { scroll-behavior: smooth; }- 检查开发者工具的「Computed」面板,确认
html元素的scroll-behavior确实是smooth,而不是被modern-normalize或 Ant Design 等框架悄悄覆盖成auto - 避免通配符重置:
* { scroll-behavior: auto !important; }会直接干掉你的设置 - 如果页面用了
height: 100vh+overflow: hidden布局(比如某些 SPA 路由容器),html实际不可滚动,属性自然不触发
锚点跳转“瞬移”?先查这三处链路断点
scroll-behavior: smooth 不是魔法开关,它只在原生锚点跳转链路完整时才起效。失效几乎从不因为 CSS 写错,而是目标找不到或算不准。
-
href和目标id必须严格一致:大小写、连字符、下划线都不能差,#contact-us对应id="contact-us"可以,#contact_us就不行 - 目标元素不能被隐藏:
display: none、visibility: hidden、父级overflow: hidden或transform都会让浏览器无法获取其位置 - 目标必须在默认文档流中:如果用了
position: absolute脱离布局,或被包在overflow: auto的局部滚动容器里,html上的scroll-behavior就管不到它
固定头部遮住锚点?用 scroll-margin-top,别算偏移量
滚动后内容被 position: fixed 或 sticky 导航栏盖住,不是滚动不准,是浏览器默认把目标顶部对齐视口顶部——这个逻辑本身没考虑头部高度。
立即学习“前端免费学习笔记(深入)”;
最稳定解法是给目标元素加 scroll-margin-top,让滚动终点自动上移:
h2[id] { scroll-margin-top: 60px; }- 值建议与导航栏实际高度一致;响应式场景可用
clamp(50px, 8vh, 80px) - 不要给
html或body加scroll-padding-top——它控制整个视口内边距,和锚点定位无关 - 这个属性和
scroll-behavior是搭档关系,缺一不可
iOS Safari 和系统“减少动画”设置会静默禁用它
scroll-behavior: smooth 在 iOS Safari 上支持极差:Safari ≤15.3 完全不支持;15.4–16.0 支持但常卡顿、跳帧甚至静默失败;iOS 16+ 仅对 element.scrollIntoView({ behavior: 'smooth' }) 有效,html 上的声明基本被忽略。
- 系统「辅助功能 → 减少动画」开启时,所有平滑滚动都会退化为瞬移,且无任何报错
- 动态渲染场景(Vue/React)中,目标元素若未挂载完成就触发跳转,
offsetTop可能为 0,导致 JS 补偿也失效 - 真正难调的不是 CSS 写法,而是当 hash 在节点挂载前就存在时,
:target伪类永远不触发——这种场景必须靠监听hashchange手动滚动


















