CSS 实现视差滚动效果

使用 background-attachment 和 transform3D 实现视差滚动

问题

如何使用 CSS 实现视差滚动效果?

解答

视差滚动(Parallax Scrolling)是指多层背景以不同的速度移动,形成立体的运动效果。网页可以分为背景层、内容层、悬浮层,当滚动时各图层以不同速度移动,产生视觉差效果。

方法一:background-attachment

background-attachment 设置为 fixed,让背景相对于视口固定,即使元素有滚动机制,背景也不会随内容滚动。

section {
    height: 100vh;
}

.g-img {
    background-image: url(...);
    background-attachment: fixed;
    background-size: cover;
    background-position: center center;
}

完整示例:

<style>
div {
    height: 100vh;
    background: rgba(0, 0, 0, .7);
    color: #fff;
    line-height: 100vh;
    text-align: center;
    font-size: 20vh;
}

.a-img1 {
    background-image: url(...);
    background-attachment: fixed;
    background-size: cover;
    background-position: center center;
}
</style>

<div class="a-img1">图层1</div>
<div>内容区域</div>
<div class="a-img1">图层2</div>

方法二:transform: translate3D

利用 3D 变换和透视实现视差效果。原理是:

容器设置 perspectivetransform-style: preserve-3d,子元素处于 3D 空间中。子元素设置不同的 translateZ() 值,在 Z 轴方向距离屏幕的距离不同。滚动时,不同 translateZ() 的元素滚动距离相对屏幕也不同,形成视差效果。

<style>
html {
    overflow: hidden;
    height: 100%;
}

body {
    /* 视差元素的父级需要3D视角 */
    perspective: 1px;
    transform-style: preserve-3d; 
    height: 100%;
    overflow-y: scroll;
    overflow-x: hidden;
}

#app {
    width: 100vw;
    height: 200vh;
}

.background {
    transform: translateZ(-1px) scale(2);
}

.foreground {
    transform: translateZ(0);
}
</style>

<body>
    <div id="app">
        <div class="background">背景层</div>
        <div class="foreground">前景层</div>
    </div>
</body>

关键点

  • background-attachment: fixed 让背景固定在视口,不随元素内容滚动
  • perspective 定义 3D 空间的透视效果,配合 transform-style: preserve-3d 使用
  • translateZ() 设置不同值让元素在 Z 轴上距离不同,滚动时产生不同的移动速度
  • translateZ() 为负值时需要用 scale() 放大元素,避免元素因透视变小