Skip to content

CSS Scroll Snap 滚动吸附效果

图片轮播、全屏滚动页面、横向滚动卡片——这些常见的交互效果过去往往需要依赖 JavaScript 库实现。CSS Scroll Snap 属性让我们可以用纯 CSS 实现滚动吸附效果,性能更好、代码更简洁。2019 年,Scroll Snap 已经获得了主流浏览器的广泛支持。本文将系统讲解 Scroll Snap 的用法和实战案例。

核心概念

Scroll Snap 涉及两个关键属性:

  • scroll-snap-type — 设置在滚动容器上,定义滚动轴和吸附严格程度
  • scroll-snap-align — 设置在子元素上,定义吸附位置

基础用法:水平轮播

html
<div class="carousel">
  <div class="slide slide-1">Slide 1</div>
  <div class="slide slide-2">Slide 2</div>
  <div class="slide slide-3">Slide 3</div>
  <div class="slide slide-4">Slide 4</div>
</div>
css
.carousel {
  display: flex;
  overflow-x: auto;
  /* 设置滚动吸附 */
  scroll-snap-type: x mandatory;
  /* 隐藏滚动条(可选) */
  -webkit-overflow-scrolling: touch;
  /* 平滑滚动 */
  scroll-behavior: smooth;
}

/* 隐藏滚动条但保留滚动功能 */
.carousel::-webkit-scrollbar {
  display: none;
}

.slide {
  /* 每个 slide 占满一屏 */
  min-width: 100vw;
  height: 100vh;
  /* 设置吸附位置 */
  scroll-snap-align: start;
  /* 居中内容 */
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
}

.slide-1 { background: #ff6b6b; color: white; }
.slide-2 { background: #4ecdc4; color: white; }
.slide-3 { background: #45b7d1; color: white; }
.slide-4 { background: #96ceb4; color: white; }

scroll-snap-type 详解

css
/* 语法 */
scroll-snap-type: <axis> <strictness>;

/* axis: x | y | block | inline | both */
scroll-snap-type: x;       /* 水平方向 */
scroll-snap-type: y;       /* 垂直方向 */
scroll-snap-type: both;    /* 两个方向 */
scroll-snap-type: block;   /* 文本流方向(与 writing-mode 相关) */
scroll-snap-type: inline;  /* 行内方向 */

/* strictness: none | proximity | mandatory */
scroll-snap-type: x mandatory;   /* 严格吸附,必须对齐到吸附点 */
scroll-snap-type: x proximity;   /* 宽松吸附,尽量对齐但不强制 */
  • mandatory — 滚动停止时必须对齐到吸附点。适用于轮播图、全屏滚动等精确场景
  • proximity — 滚动停止时尽量对齐,但位置不够精确时不会强制调整。适用于长列表等自然滚动场景

scroll-snap-align 详解

css
/* 语法 */
scroll-snap-align: <alignment>;

/* alignment: none | start | center | end | <value> <value> */
scroll-snap-align: start;    /* 子元素起始边对齐容器起始边 */
scroll-snap-align: center;   /* 子元素中心对齐容器中心 */
scroll-snap-align: end;      /* 子元素结束边对齐容器结束边 */
scroll-snap-align: start end; /* 第一个值:行内方向,第二个值:块方向 */

全屏滚动页面

html
<div class="fullpage-scroll">
  <section class="section" id="home">首页</section>
  <section class="section" id="about">关于</section>
  <section class="section" id="work">作品</section>
  <section class="section" id="contact">联系</section>
</div>
css
.fullpage-scroll {
  height: 100vh;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  scroll-behavior: smooth;
}

.section {
  height: 100vh;
  scroll-snap-align: start;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 3rem;
}

#home { background: linear-gradient(135deg, #667eea, #764ba2); color: white; }
#about { background: linear-gradient(135deg, #f093fb, #f5576c); color: white; }
#work { background: linear-gradient(135deg, #4facfe, #00f2fe); color: white; }
#contact { background: linear-gradient(135deg, #43e97b, #38f9d7); color: white; }

卡片列表吸附

适用于产品展示、文章列表等场景:

html
<div class="card-container">
  <div class="card">Card 1</div>
  <div class="card">Card 2</div>
  <div class="card">Card 3</div>
  <div class="card">Card 4</div>
  <div class="card">Card 5</div>
</div>
css
.card-container {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  padding: 20px;
  scroll-snap-type: x proximity;  /* 宽松吸附 */
  /* 让边缘的卡片也能居中显示 */
  scroll-padding: 0 calc(50% - 150px);
}

.card {
  min-width: 300px;
  height: 200px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  scroll-snap-align: center;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  transition: transform 0.3s;
}

.card:hover {
  transform: scale(1.02);
}

scroll-snap-stop 控制滚动穿透

默认情况下,快速滑动可能跳过多个吸附点。scroll-snap-stop 可以控制这个行为:

css
.slide {
  scroll-snap-align: start;
  /* normal: 允许跳过 | always: 每次必须停留 */
  scroll-snap-stop: always;
}

这个属性特别适合需要用户逐页阅读的场景,如新手引导页。

scroll-padding 和 scroll-margin

scroll-padding(设置在容器上)

在滚动容器内设置内边距,不影响布局但影响吸附位置:

css
/* 有固定导航栏时,避免内容被遮挡 */
.fullpage-scroll {
  scroll-snap-type: y mandatory;
  scroll-padding-top: 60px; /* 导航栏高度 */
}

.section {
  scroll-snap-align: start;
}

scroll-margin(设置在子元素上)

为单个子元素设置外边距:

css
.section {
  scroll-snap-align: start;
  scroll-margin-top: 60px; /* 仅这个 section 有顶部偏移 */
}

实战:图片画廊

html
<div class="gallery">
  <div class="gallery-item">
    <img src="photo1.jpg" alt="照片1">
  </div>
  <div class="gallery-item">
    <img src="photo2.jpg" alt="照片2">
  </div>
  <div class="gallery-item">
    <img src="photo3.jpg" alt="照片3">
  </div>
</div>
css
.gallery {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  gap: 10px;
  padding: 10px;
  scroll-padding: 10px;
}

.gallery-item {
  scroll-snap-align: center;
  scroll-snap-stop: always;
  flex: 0 0 auto;
  border-radius: 8px;
  overflow: hidden;
}

.gallery-item img {
  height: 300px;
  width: auto;
  object-fit: cover;
  display: block;
}

垂直内容导航

配合侧边导航使用,实现点击导航自动滚动:

html
<div class="layout">
  <nav class="side-nav">
    <a href="#section1">第一节</a>
    <a href="#section2">第二节</a>
    <a href="#section3">第三节</a>
  </nav>
  <main class="content">
    <section id="section1">内容一</section>
    <section id="section2">内容二</section>
    <section id="section3">内容三</section>
  </main>
</div>
css
.content {
  height: 100vh;
  overflow-y: auto;
  scroll-snap-type: y proximity;
  scroll-behavior: smooth;
}

section {
  min-height: 100vh;
  scroll-snap-align: start;
  padding: 40px;
  border-bottom: 1px solid #eee;
}

浏览器兼容性

2019 年 8 月的支持情况:

  • Chrome 69+ — 完整支持
  • Firefox 68+ — 完整支持
  • Safari 11+ — 完整支持(需要 -webkit- 前缀)
  • Edge 79+ — 完整支持
  • IE — 不支持

对于不支持的浏览器,可以添加渐进增强:

css
@supports (scroll-snap-type: x mandatory) {
  .carousel {
    scroll-snap-type: x mandatory;
  }
  .slide {
    scroll-snap-align: start;
  }
}

/* 不支持的浏览器仍然可以正常使用滚动,只是没有吸附效果 */

小结

  • scroll-snap-type 设置在容器上定义滚动轴和吸附严格度,scroll-snap-align 设置在子元素上定义吸附位置
  • mandatory 严格吸附适用于轮播图等精确场景,proximity 宽松吸附适用于列表等自然滚动场景
  • scroll-snap-stop: always 可以防止快速滑动时跳过内容
  • scroll-paddingscroll-margin 用于处理固定导航栏等偏移场景
  • 使用 @supports 做渐进增强,不支持的浏览器仍可正常使用滚动功能
  • 纯 CSS 实现,性能优于 JavaScript 方案,推荐在新项目中优先使用

MIT Licensed