CSS实现滚动贴合效果

发布时间 2023-12-28 11:17:18作者: 周文豪

一、滚动贴合介绍

滚动贴合:鼠标滚动的时候,自动贴合到浏览器的底部或顶部

设置CSS滚动贴合需要使用到两个属性:

1、给滚动容器设置scroll-snap-type,值为滚动的方向和方式

.container {
            /* display: flex; */
            /* 第一个值为滚动贴合的方向,y表示纵向滚动贴合,
            第二个值表示贴合方式,mandatory表示强制滚动 */
            scroll-snap-type: y mandatory;
        }

2、给滚动的内容设置scroll-snap-align,即滚动贴合的对齐方式,值为start、center、end

.child{
            /* 设置子元素的贴合对齐方式 */
            scroll-snap-align: center;
        }

二、未使用滚动贴合时的效果

使用之前代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        main {
            /* 需要把滚动条设置到直接父容器,
            scroll-snap-type才能生效,
            默认是再body上,现在是在main上 */
            overflow: scroll;
            height: 100vh;
        }
        section{
            width: 100vw;
            height: 100vh;
        }
        /* 给每个页面设置不同的颜色用于区分 */
        main > section:nth-child(1){
            background-color: #7f97ae;
        }
        main > section:nth-child(2){
            background-color: #c6b9a3;
        }
        main > section:nth-child(3){
            background-color: #bbcadc;
        }
        main > section:nth-child(4){
            background-color: #d7c6d9;
        }
        main > section:nth-child(5){
            background-color: #bfbea8;
        }
    </style>
</head>
<body>
    <main>
        <section>页面内容1</section>
        <section>页面内容2</section>
        <section>页面内容3</section>
        <section>页面内容4</section>
    </main>
</body>
</html>

效果如下:

发现用鼠标滚轮滚动时,页面不会自动贴合到浏览器的顶部或者底部

三、使用滚动贴合

假设我们有四屏的内容需要垂直滚动贴合,我们用main元素表示滚动的容器,四个section表示要滚动贴合的内容。

每个section都设置为占满全屏,即宽为100vw,高为100vh。

使用之后的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        main {
            /* 第一个值为滚动贴合的方向,y表示纵向滚动贴合,
            第二个值表示贴合方式,mandatory表示强制滚动 */
            scroll-snap-type: y mandatory;
            /* 需要把滚动条设置到直接父容器,
            scroll-snap-type才能生效,
            默认是再body上,现在是在main上 */
            overflow: scroll;
            height: 100vh;
        }
        section{
            width: 100vw;
            height: 100vh;
            /* 设置子元素的贴合对齐方式 start表示下一屏的内容会直接贴合到main元素的顶部*/
            scroll-snap-align: start;
        }
        /* 给每个页面设置不同的颜色用于区分 */
        main > section:nth-child(1){
            background-color: #7f97ae;
        }
        main > section:nth-child(2){
            background-color: #c6b9a3;
        }
        main > section:nth-child(3){
            background-color: #bbcadc;
        }
        main > section:nth-child(4){
            background-color: #d7c6d9;
        }
        main > section:nth-child(5){
            background-color: #bfbea8;
        }
    </style>
</head>
<body>
    <main>
        <section>页面内容1</section>
        <section>页面内容2</section>
        <section>页面内容3</section>
        <section>页面内容4</section>
    </main>
</body>
</html>

效果如下:

这样就实现了滚动贴合的效果

(1)、如果我们把section的高度加长为150vh,再把scroll-snap-align的属性设置为end,那么滚动的时候,下一屏内容的底部就会贴合到main元素的底部

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        main {
            /* 第一个值为滚动贴合的方向,y表示纵向滚动贴合,
            第二个值表示贴合方式,mandatory表示强制滚动 */
            scroll-snap-type: y mandatory;
            /* 需要把滚动条设置到直接父容器,
            scroll-snap-type才能生效,
            默认是再body上,现在是在main上 */
            overflow: scroll;
            height: 100vh;
        }
        section{
            width: 100vw;
            height: 150vh;
            /* 设置子元素的贴合对齐方式 */
            scroll-snap-align: end;
        }
        /* 给每个页面设置不同的颜色用于区分 */
        main > section:nth-child(1){
            background-color: #7f97ae;
        }
        main > section:nth-child(2){
            background-color: #c6b9a3;
        }
        main > section:nth-child(3){
            background-color: #bbcadc;
        }
        main > section:nth-child(4){
            background-color: #d7c6d9;
        }
        main > section:nth-child(5){
            background-color: #bfbea8;
        }
    </style>
</head>
<body>
    <main>
        <section>页面内容1</section>
        <section>页面内容2</section>
        <section>页面内容3</section>
        <section>页面内容4</section>
    </main>
</body>
</html>

效果如下:

(2)、如果我们把section的高度加长为150vh,再把scroll-snap-align的属性设置为center,那么滚动的时候,下一屏内容就会和main元素垂直居中对齐

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        main {
            /* display: flex; */
            /* 第一个值为滚动贴合的方向,y表示纵向滚动贴合,
            第二个值表示贴合方式,mandatory表示强制滚动 */
            scroll-snap-type: y mandatory;
            /* 需要把滚动条设置到直接父容器,
            scroll-snap-type才能生效,
            默认是再body上,现在是在main上 */
            overflow: scroll;
            height: 100vh;
        }
        section{
            width: 100vw;
            height: 150vh;
            /* 设置子元素的贴合对齐方式 */
            scroll-snap-align: center;
        }
        /* 给每个页面设置不同的颜色用于区分 */
        main > section:nth-child(1){
            background-color: #7f97ae;
            display: flex;
            justify-content: center;
            align-items: center;
            
        }
        main > section:nth-child(2){
            background-color: #c6b9a3;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        main > section:nth-child(3){
            background-color: #bbcadc;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        main > section:nth-child(4){
            background-color: #d7c6d9;
            display: flex;
            justify-content: center;
            align-items: center;
        }
    </style>
</head>
<body>
    <main>
        <section>页面内容1</section>
        <section>页面内容2</section>
        <section>页面内容3</section>
        <section>页面内容4</section>
    </main>
</body>
</html>

效果如下:

四、水平滚动贴合

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        main {
            display: flex;
            /* 第一个值为滚动贴合的方向,y表示纵向滚动贴合,
            第二个值表示贴合方式,mandatory表示强制滚动 */
            scroll-snap-type: x mandatory;
            /* 需要把滚动条设置到直接父容器,
            scroll-snap-type才能生效,
            默认是再body上,现在是在main上 */
            overflow: scroll;
            width: 100vw;
            height: 100vh;
        }
        section{
            width: 100vw;
            height: 100vh;
            /* 设置子元素的贴合对齐方式 */
            scroll-snap-align: center;
            flex-shrink: 0;
        }
        /* 给每个页面设置不同的颜色用于区分 */
        main > section:nth-child(1){
            background-color: #7f97ae;
            display: flex;
            justify-content: center;
            align-items: center;
            
        }
        main > section:nth-child(2){
            background-color: #c6b9a3;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        main > section:nth-child(3){
            background-color: #bbcadc;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        main > section:nth-child(4){
            background-color: #d7c6d9;
            display: flex;
            justify-content: center;
            align-items: center;
        }
    </style>
</head>
<body>
    <main>
        <section>页面内容1</section>
        <section>页面内容2</section>
        <section>页面内容3</section>
        <section>页面内容4</section>
    </main>
</body>
</html>

效果如下:

五、使用proximity小于一定距离的时候进行贴合

使用mandatory强制贴合的方式,适合内容尺寸较小的情况,如果有的元素内容非常长,那么在滚动的时候,会直接滑动到下一屏,导致不在屏幕上的内容很快就会滑过,这时候,我们可以把scroll-snap-type属性的第二个值改为proximity,这样让元素滚动到离贴合点小于一定距离的时候再进行贴合,这个距离是根据浏览器自己规定的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        main {
            /* 第一个值为滚动贴合的方向,y表示纵向滚动贴合,
            第二个值表示贴合方式,mandatory表示强制滚动 */
            scroll-snap-type: y proximity;
            /* 需要把滚动条设置到直接父容器,
            scroll-snap-type才能生效,
            默认是再body上,现在是在main上 */
            overflow: scroll;
            height: 100vh;
        }
        section{
            width: 100vw;
            height: 100vh;
            /* 设置子元素的贴合对齐方式 */
            scroll-snap-align: end;
        }
        /* 给每个页面设置不同的颜色用于区分 */
        main > section:nth-child(1){
            background-color: #7f97ae;
            display: flex;
            justify-content: center;
            align-items: center;
            
        }
        main > section:nth-child(2){
            background-color: #c6b9a3;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        main > section:nth-child(3){
            background-color: #bbcadc;
            height: 250vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        main > section:nth-child(4){
            background-color: #d7c6d9;
            display: flex;
            justify-content: center;
            align-items: center;
        }
    </style>
</head>
<body>
    <main>
        <section>页面内容1</section>
        <section>页面内容2</section>
        <section>页面内容3</section>
        <section>页面内容4</section>
    </main>
</body>
</html>

效果如下:

六、设置sticky头部时的滚动贴合

在贴合的时候,我们还可以给容器设置间距,让贴合点偏离浏览器底部或顶部一些距离,当有一个position为sticky头部时,由于它占据了一定的空间,如果直接设置滚动贴合,那么元素会贴合到main元素的顶部,这样会有一部分内容被sticky头部覆盖,这种情况下我们可以给滚动的容器main元素设置scroll-padding,大小跟sticky头部的高度一致,这样就能在贴合的时候,与main元素有一定的间距,从而把头部的空间流出来。

scroll-padding和padding的取值方式是一样的,分别是上右下左

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        main {
            /* 第一个值为滚动贴合的方向,y表示纵向滚动贴合,
            第二个值表示贴合方式,mandatory表示强制滚动 */
            scroll-snap-type: y mandatory;
            scroll-padding: 80px;
            /* 需要把滚动条设置到直接父容器,
            scroll-snap-type才能生效,
            默认是再body上,现在是在main上 */
            overflow: scroll;
            height: 100vh;
        }
        h1{
            height: 80px;
            position: sticky;
            top: 0;
            background-color: red;
        }
        section{
            width: 100vw;
            height: 100vh;
            /* 设置子元素的贴合对齐方式 */
            scroll-snap-align: start;
        }
        /* 给每个页面设置不同的颜色用于区分 */
        main > section:nth-child(2){
            background-color: #7f97ae;
            
        }
        main > section:nth-child(3){
            background-color: #c6b9a3;
        }
        main > section:nth-child(4){
            background-color: #bbcadc;
        }
        main > section:nth-child(5){
            background-color: #663d69;
        }
    </style>
</head>
<body>
    <main>
        <h1>H1标题</h1>
        <section>页面内容1</section>
        <section>页面内容2</section>
        <section>页面内容3</section>
        <section>页面内容4</section>
    </main>
</body>
</html>

效果:

七、列表滚动

滚动贴合不仅仅可以用于全屏滚动,也可以用于ul这种小的列表滚动

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        main {
            width: 100vw;
            height: 100vh;
            display: grid;
            place-items: center;
        }
        ul{
            width: 200px;
            height: 200px;
            scroll-snap-type: y mandatory;
            overflow-y:scroll;  /*只是y方向*/
            list-style: none;
            /* 隐藏x向滚动条 */
            overflow-x: hidden;
            
        }
        li{
            scroll-snap-align: start;
        }
        /* 给每个页面设置不同的颜色用于区分 */
        ul > li:nth-child(1){
            background-color: #7f97ae;
            width: 200px;
            height: 200px;
            
        }
        ul > li:nth-child(2){
            background-color: #c6b9a3;
            width: 200px;
            height: 200px;
        }
        ul > li:nth-child(3){
            background-color: #bbcadc;
            width: 200px;
            height: 200px;
        }
        ul > li:nth-child(4){
            background-color: #663d69;
            width: 200px;
            height: 200px;
        }
    </style>
</head>
<body>
    <main>
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>
    </main>
</body>
</html>

效果如下: