CSS Handbook · 现代布局特性

第九章 / 9.2 scroll-snap 与滚动行为

第九章 · 9.2 节

scroll-snap 与滚动行为


"滑动到某张卡片会自动对齐"这类交互,过去只能靠 JavaScript 监听滚动事件手动计算实现。CSS 滚动捕捉(Scroll Snap)把这类效果变成了纯 CSS 方案,性能更好,也天然支持触摸滑动手势。

scroll-snap 基础三件套

属性作用对象说明
scroll-snap-type滚动容器开启捕捉,指定轴向与强制程度
scroll-snap-align子项该子项对齐容器的哪个边缘
scroll-snap-stop子项是否强制每次只能停留一个子项,禁止快速滑动跳过
.container {
  overflow-x: auto;
  scroll-snap-type: x mandatory; /* x 轴,mandatory 强制吸附 */
}
.item {
  scroll-snap-align: center;
}

scroll-snap-type 的第二个参数决定"强制程度":mandatory 滚动停止后必定吸附到最近的捕捉点;proximity 仅在离捕捉点足够近时才吸附,否则停在原地,体验更"自由"。

scroll-snap-type: x mandatory(可横向滑动)
1
2
3
4

这与 6.3 Flexbox 详解 中的横向布局结合,是移动端"卡片轮播"最轻量的实现方式,无需引入任何 JS 轮播库。

整屏滚动示例

html {
  scroll-snap-type: y mandatory;
}
section {
  height: 100vh;
  scroll-snap-align: start;
}

这是纯 CSS 实现"整屏切换"落地页效果的核心代码,每个 section 占满一屏,滚动时自动吸附对齐到顶部。

scroll-behavior 平滑滚动

点击锚点链接或调用 scrollIntoView() 时,默认是瞬间跳转。scroll-behavior: smooth 让这个过程变成平滑动画,同样无需 JavaScript。

html {
  scroll-behavior: smooth;
}

scroll-margin 与锚点偏移

页面存在固定定位的顶部导航栏时,直接跳转锚点会导致目标区域被导航栏遮住一部分。scroll-margin-top 可以为锚点滚动预留出这段偏移,而不影响元素本身的布局。

h2[id] {
  scroll-margin-top: 72px; /* 等于固定导航栏的高度 */
}

常见误区

  • 设置了 scroll-snap-type 却忘记容器需要有 overflow: auto/scroll 才能真正产生可滚动区域。
  • 整屏滚动场景中,子项高度不是 100vh 或存在外边距,导致捕捉位置出现细微偏差。
  • 只关注 scroll-behavior: smooth 而忽视了它对"辅助功能用户"可能造成的眩晕感,建议配合 prefers-reduced-motion 媒体特性关闭平滑滚动(详见 5.2 常用媒体特性)。

Chapter 9 · Section 9.2

scroll-snap and Scrolling Behavior


Interactions like "a card snaps into place when you swipe to it" used to require JavaScript that listened to scroll events and computed positions by hand. CSS Scroll Snap turns this into a pure CSS solution — better performance, with native support for touch swipes.

The Three Basic scroll-snap Properties

PropertyApplies toDescription
scroll-snap-typeScroll containerEnables snapping; sets the axis and how forcefully it snaps
scroll-snap-alignChild itemsWhich edge of the container the item aligns to
scroll-snap-stopChild itemsWhether each stop must land on exactly one item, preventing fast swipes from skipping over
.container {
  overflow-x: auto;
  scroll-snap-type: x mandatory; /* x axis; mandatory snaps forcefully */
}
.item {
  scroll-snap-align: center;
}

The second argument of scroll-snap-type sets how forcefully it snaps: with mandatory, scrolling always settles on the nearest snap point; with proximity, it only snaps when you stop close enough to a snap point, otherwise it stays where it is — a freer feel.

Horizontal Card Gallery Example

scroll-snap-type: x mandatory (swipe horizontally)
1
2
3
4

Combined with the horizontal layout from 6.3 Flexbox in Depth, this is the lightest way to build a mobile "card carousel" — no JavaScript carousel library needed.

Full-Screen Scrolling Example

html {
  scroll-snap-type: y mandatory;
}
section {
  height: 100vh;
  scroll-snap-align: start;
}

This is the core CSS for a pure-CSS full-screen "page transition" landing page: every section fills one viewport, and scrolling snaps each one to the top.

scroll-behavior: Smooth Scrolling

Clicking an anchor link or calling scrollIntoView() jumps instantly by default. scroll-behavior: smooth turns this into a smooth animation — again, no JavaScript needed.

html {
  scroll-behavior: smooth;
}

scroll-margin and Anchor Offsets

When the page has a fixed top navbar, jumping to an anchor hides part of the target behind the navbar. scroll-margin-top reserves that offset for anchor scrolling without affecting the element's own layout.

h2[id] {
  scroll-margin-top: 72px; /* equals the fixed navbar's height */
}

Common Pitfalls

  • Setting scroll-snap-type but forgetting that the container needs overflow: auto/scroll to actually produce a scrollable area.
  • In full-screen scrolling, child heights that are not 100vh, or existing margins, cause slight misalignment of the snap positions.
  • Focusing only on scroll-behavior: smooth while ignoring the motion sickness it can cause for assistive-technology users; consider disabling smooth scrolling with the prefers-reduced-motion media feature (see 5.2 Common Media Features).