基于CSS3-perspective的视差滚动

3,843 阅读3分钟

前情提要:本篇文章已经默认你已经彻底了解perspective和translateZ的含义与用法,如果尚未了解,我推荐你看css3系列之详解perspective

Part1 什么是视差滚动?

视差滚动示意图.png 如图所示,紫div和红div的滚动速度是不同的,比如用户滚动了300px,但红div按1:2,只滚动了150px,而紫色div按1:1,滚动了300px。

最终形成了多个div滚动距离不一致,体现了"视差"的效果,简单的来说,就是视差滚动,它的原理就是滚动速度不一致!

你问这有什么用? 那么你可以尝试访问这个网站 www.firewatchgame.com/ 试试在该页面上滚动滑轮吧!

是不是比起普通网站多了一层酷炫?想知道如何实现吗?接下来我们进入part2。

Part2 视差滚动的实现

步骤: 1.建立一个容器元素,设置 overflow-y: scroll 使其可以滚动(同时可能需要 overflow-x: hidden)。

2.对于上面的元素, 我们会应用一个 perspective 值,然后设置 perspective-origin 到 top left, 或者 0 0。

3.对上面元素的子元素应用一个在 Z 轴的变换,然后把它们还原回来以实现视差效果,而没有影响它们在屏幕上的大小。 这种方案下的css和html:

.container {
  width: 100%;
  height: 100%;
  overflow-x: hidden;
  overflow-y: scroll;
  perspective: 1px;
}

.parallax-child {
  transform: translateZ(-2px) scale(3);
}

是不是很简单?

<div class="container”>
  <div class="parallax-child”></div>
</div>

现在的你已经写出基本的视差滚动动画了!但是perspective和translateZ是怎么影响滚动速度的?还有scale,为什么这里设置的是3?想知道吗?那么接下来进入part3

Part 3 原理解析

这里把scale设为S,pespcetive->P,translateZ->D //注意D一般是负值 那么有公式S=(P-D)/P, 这个公式怎么来的?这其实就是一个简单的相似三角形 image.png

划红线的地方的比例就是1:3,那么你只需要在原来的基础上放大3就可以让图形变回原来的比例,这里的1就是P,2就是D,那么很容易发现图形的缩小比例是P/(P-D),想放大回来?倒置这个缩小比例即可,我们便得到了S=(P-D)/P 现在我们已经靠scale属性让图形变回了原来的大小,似乎一切都恢复了原状,但有一个东西,它变了,便是滚动速度,滚动速度和上面的缩小比例是完全一致的,以如下数据为例

父元素
perspective: 1px;
子元素
transform: translateZ(-2px) scale(3);

不看scale,这里的缩小比例是1/3,那么由于css机制,它的滚动速度也会变成原来的1/3。即使添加了scale属性,它的滚动速度依然不变还是原来的1/3。

现在让我们来总结性质: 父元素设置perspective,子元素设置 translateZ(-2px),那么无论是否有scale属性, 则有

缩小比例=滚动速度比=P/(P-D)

PS:如果不设置 translateZ,或者 translateZ(0),那么对应D=0,所以有缩小比例=滚动速度比=(P/P-0)=1:1,即相对于原来的滚动速率不变。

为了方便读者尝试,我码了一个小小的demo,你可以任意更改属性来验证上面的结论!

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <style>
    html,
    body {
      margin: 0;
      font-family: Helvetica, "PingFang SC",
        "Microsoft Yahei", sans-serif;
        background:#00b894;
        display: flex;
        justify-content: center;
        align-items:center;
        height:100vh;
    }
    * {
      box-sizing: border-box;
    }
    .container {
      width: 50vh;
      height: 50vh;
      overflow-x: hidden;
      overflow-y: scroll;
      perspective: 1px;
    }

    .parallax-child {
      width:50vh;
      height:50vh;
      border:1px solid black;
      /* transform-origin: 0 0; */
     transform: translateZ(-2px) scale(3);
      background:rgba(255,255,255,0.5)
    }
    .another{
      width:50vh;
      height:50vh;
      border:1px solid black;
      background:rgba(0,0,0,0.5)
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="parallax-child"></div>
    <div class="another">2333333333333333</div>
  </div>
</body>
</html>

参考:

Performant Parallaxing :developers.google.com/web/updates…

[杨耿]css3系列之详解perspective: www.cnblogs.com/yanggeng/p/…