面试官:用css实现视差滚动效果😒,我:茴香豆的茴有三种写法🚀,面试官:?你说多少?😱

2,870 阅读8分钟

这其实是老生常谈的问题了,但是因为最近有小伙伴面试被问到了,找到我想让我讲解下,所以我还是打算写一篇文章介绍下。 如果对您有用的话话,不妨评论,点赞关注➕收藏。

视差滚动

视差滚动是一种效果,能够使不同层次的元素以不同的速度进行滚动,从而产生了视觉上的深度感和动态效果,比如下面这个视频。 8c3578b0-6a73-4b28-94d8-0047b1678fa8.gif

background-attachment

先来介绍下background-attachment这个属性

background-attachment 算是一个比较生僻的属性,基本上平时写业务样式都用不到这个属性。但是它本身很有意思。

简单了解下相关属性

  • background-attachment: scroll:scroll 此关键字表示背景相对于元素本身固定, 而不是随着它的内容滚动。

  • background-attachment: local:local 此关键字表示背景相对于元素的内容固定。如果一个元素拥有滚动机制,背景将会随着元素的内容滚动, 并且背景的绘制区域和定位区域是相对于可滚动的区域而不是包含他们的边框。

  • background-attachment: fixed:fixed 此关键字表示背景相对于视口固定。即使一个元素拥有滚动机制,背景也不会随着元素的内容滚动。

🔥茴:一种写法background-attachment: fixed

这里的关键在于,即使一个元素拥有滚动机制,背景也不会随着元素的内容滚动。也就是说,背景图从一开始就已经被固定死在初始所在的位置。

section {
    height: 100vh;
    background: rgba(0, 0, 0, .7);
    color: #fff;
    line-height: 100vh;
    text-align: center;
    font-size: 20vh;
}
.g-img1 {
    background-image: url("./assets/11.jpg");
    
    //🚀🔥重点看这里
    background-attachment: fixed;
    background-size: cover;
    background-position: center center;
}

.g-img2 {
    background-image: url("./assets/12.jpg");
    
    //🚀🔥重点看这里
    background-attachment: fixed;
    background-size: cover;
    background-position: center center;
}

.g-img3 {
    background-image: url("./assets/13.jpg");
    
    //🚀🔥重点看这里
    background-attachment: fixed;
    background-size: cover;
    background-position: center center;
}
  </style>
  <section class="g-word">Header</section>
  <section class="g-img1">IMG1</section>
  <section class="g-word">Content1</section>
  <section class="g-img2">IMG2</section>
  <section class="g-word">Content2</section>
  <section class="g-img3">IMG3</section>
  <section class="g-word">Footer</section>
</html>

80c415cf-c11b-4336-9b91-61c59b565078.gif

可能大家第一看会懵逼😄,你可以将background-attachment: fixed 注释掉,或者改为 background-attachment: local来理解一下 这里就不演示了,大家自行尝试

这里我们把没有图片的全部去掉,发现就很好看了。 8c3578b0-6a73-4b28-94d8-0047b1678fa8.gif

缺点:这种方法很单一,适用于静态页面

下面这种方法可以创建更复杂的视差效果,适用于更灵活的需求。

🚀茴的第二种写法:transform-style: preserve-3d以及perspective;

这里默认大家都认识这两个元素,所以我不会深入去讲解它们。

上面的例子无法掩饰,因为文字就在图片上,无法进行3D转换,这里我给大家重新写了一个。

html {
  height: 100vh;
  overflow: hidden;
}
body {
  width: 100vw;
  height: 100vh;
  margin: 0;
  background: #222;

  /* 设置景深,并且开启3D效果 */
  perspective: 1px;
  transform-style: preserve-3d;

  overflow-x: hidden;
  overflow-y: scroll;
}

.section1::before {
  content: "";
  width: 100%;
  height: 100%;
  position: absolute;
  background: url("./assets/11.jpg") top center;
  background-size: cover;

  /* 将图片图层换到-1图层,并放大图片 */
  transform: translateZ(-1px) scale(2.2);
}
.section1, .section2 {
  width: 100%;
  min-height: 100vh;
  position: relative;
  
  //保留字类的3D属性
  transform-style: preserve-3d;

}

.section2 {
  background: rgb(68, 35,19);
}

//给文字添加样式以及定位
.text {
  top:30%;
  left: 50%;
  position: absolute;
  font-size: 15vw;
  font-family: 'Franklin Gothic Heavy';
  font-size: 15vw;
  color: white;
  text-shadow: 2px 2px 5px rgba(0,0,0,0.3),5px 5px 70px rgba(255,255,255,0.5);
  transform: scale(1,1.1) translate(-50%, 10%);
}
  <div class="section1">
    <div class="text">PARALLAX</div>
  </div>

  <div class="section2">
    <div class="text">NORMAL</div>
  </div>

ca145789-b04e-4b7c-967d-668302a39ceb.gif

可以看到我们通过 transform-style: preserve-3d以及perspective;实现了视差滚动效果。

讲解下重要代码

  • perspective :perspective 可以定义我们眼睛看到的 3d 立体效果,即空间感。所以perspective: 1px 时,我们是在告诉浏览器,以一个非常近的的距离(1 像素)来观察元素的 3D 变换。

  • transform-style: preserve-3d 时,你是在告诉浏览器,开启3D空间。

  • transform: translateZ(-1px) scale(2.2); translateZ(-1px)把元素放在-1图层,这于我们的眼睛相同,距离越远物体越小,所以我们要设置scale将其放大。

  • transform-style: preserve-3d;我们有大佬发现子元素又写了一次,这是为了让它有自己的3D样式,避免父元素的3D效果对其造成影响。

  • .section1::before: 通过 ::before 伪元素,可以将其视为一个实际的元素,具有自己的 positiontransformopacity 等属性,使得我们可以对背景图像进行 3D 变换、动画效果等操作。而这些操作使用 background-image 可能无法轻松实现。

茴的第三种写法:animation-timeline:scoll() <-这个大家酌情观看

animation-timeline是一个还在实验性特性,浏览器兼容性较差,大家这里了解即可。

先来简单介绍下它

  • animation-timeline 是 CSS 中的一个属性,它允许你将动画的时间线与特定的时间源相关联。
  • scroll() 是 animation-timeline 属性的一个函数值,它将动画的时间线与元素的滚动位置相关联。

当使用 animation-timeline: scroll(); 时,动画的进度将不再基于时间(如 animation-duration),而是基于元素的滚动位置。这意味着动画的播放进度将根据元素在滚动容器中的滚动位置来确定。

例如,如果你有一个元素正在滚动,并且该元素的子元素应用了 animation-timeline: scroll();,那么子元素的动画将根据父元素的滚动位置来播放。当你滚动页面或滚动容器时,动画会根据滚动的距离和进度进行相应的变化。

同样,我给大家准备了一个新的网站,这个网站比较炫酷,并且代码比较简单。

bc738850-60f2-4f50-9073-d53557743843.gif

为了方便讲解,我删掉不必要的元素

  <body>
    <div class="parallax">
      <img class="parallax__bg" src="assets/bg.jpg" alt="" />
      <img class="parallax__dust" src="assets/dust.webp" alt="" />
      <img
        class="parallax__foreground-back"
        src="assets/foreground-back.webp"
        alt=""
      />
      <img
        class="parallax__foreground-front"
        src="assets/foreground-front.webp"
        alt=""
      />
      <img class="parallax__jax" src="assets/jax.webp" alt="" />
      <img class="parallax__luna" src="assets/luna.webp" alt="" />
      <img class="parallax__manny" src="assets/manny.webp" alt="" />
      <img class="parallax__rays" src="assets/rays.webp" alt="" />
    </div>
.parallax {
  contain: paint;
  position: relative;
  z-index: 0;
  min-height: 75vh;
  display: grid;
  grid-template-areas: "stack";
}
.parallax > * {
  grid-area: stack;
  animation: parallax linear;
  animation-timeline: scroll();
}
@keyframes parallax {
  to {
    transform: 
      translateY(calc(var(--parallax-speed) * 200px));
  }
}

.parallax__dust {
  --parallax-speed: -20;
  z-index: 2;
}

.parallax__luna {
  --parallax-speed: 50;
  z-index: 3;
}
...后面省略一大堆类似的代码

eae29b7c-b7b9-4e61-9b70-bf87ff36ff60.gif 下面讲解下代码:

.parallax > * {
  grid-area: stack;
  animation: parallax linear;
  animation-timeline: scroll();
}

这段代码的整体功能是将 .parallax 元素的所有直接子元素放置在同一个网格区域 stack 中,并为它们应用一个名为 parallax 的线性动画以及使用了animation-timeline: scroll();去让浏览器监听滚动事件

@keyframes parallax {
  to {
    transform: 
      translateY(calc(var(--parallax-speed) * 200px));
  }
}

自定义了·parallax的垂直平移动画,通过 calc() 函数和自定义属性 --parallax-speed 可以调整动画的平移距离。

.parallax__dust {
  --parallax-speed: -20;
  z-index: 2;
}

--parallax-speed赋值以及 使用z-index 属性调整元素图层,结合 @keyframes 创建具有不同速度的动画效果。

  contain: paint;

这段代码可能大家很少见,

简单解释下:

  • contain 是一个 CSS 属性,它允许开发者指定元素的渲染范围和效果,以优化性能和布局计算。
  • contain: paint; 是 contain 属性的一个值,它表示元素的渲染只局限于元素自身的边界,不会影响到页面的其他部分,并且元素的后代元素的渲染也不会影响到元素外部的布局。

注意:这里不能用overflow:hidden,如果使用,你的动画就没了。

具体原因我也不知道😂,如果有大佬知道的话可以讲解一下。我将会万分感谢🙏 如果你非要用overflow:hidden,就给animation-timeline:scroll()传入一个root值

  • scroll(root) 是 animation-timeline 属性的一个值,它表示将动画的时间线与文档根元素(通常是 html 元素)的滚动条滚动位置相关联。

或者使用overflow:cilp也能解决。

这种方法的本质是用了动画来解决视差滚动的问题

总结

这里我们介绍了三种方法实现视差滚动,分别是

  • background-attachment
  • transform-style: preserve-3d以及perspective;
  • animation-timeline: scroll() ,这个大家酌情学习。

其实还有,但是我认为有些炫技和装逼的成分在了🌚,并且现在有很多现成的库开箱即用,所以这里不给大家继续讲解别的方法了🎇

大家学好上面三个足以应付面试和日常开发了(最后一种方法也就我讲讲了,其他文章都是上述两种方法͡° ͜ʖ ͡°)。

好了讲完啦😄,如果对您有用的话,不妨留下宝贵的评论(这个比较重要),以及点赞关注加收藏!!❤️🙏。