前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CSS | 视差滚动 | 笔记

CSS | 视差滚动 | 笔记

作者头像
yiyun
发布2023-07-24 21:28:25
5760
发布2023-07-24 21:28:25
举报
文章被收录于专栏:yiyun 的专栏yiyun 的专栏

引言

视差滚动(Parallax Scrolling)是一种效果, 能够使不同层次的元素以不同的速度进行滚动, 从而产生了视觉上的深度感和动态效果。 CSS 可以通过两种方式来实现: background-attachmenttransform:translate3D

从广义上讲,有两种方法可以使用 CSS 实现视差效果。 让我们探索和比较 固定背景位置 和 使用 3D 平移。

滚动 一般指 background-attachment 容器滚动,而背景图不滚动(固定)

视差 一般指 transform: translate3D 引起的视差效果, 但有些时候也仅仅用 background-attachment 形成的效果称之为 视差滚动

background-attachment

固定背景的位置是使用CSS创建视差效果的最早方法。 你可以将其视为 2.5D 视差实现。

background-attachment: 决定 背景图像的位置 是在 视口内固定 ,或者 随着包含它的区块滚动 。 它的属性值的含义如下:

属性值

含义

fixed

背景相对于视口固定。即使一个元素拥有滚动机制,背景也不会随着元素的内容滚动

local

背景相对于元素的内容固定。如果一个元素拥有滚动机制,背景将会随着元素的内容滚动,并且背景的绘制区域和定位区域是相对于可滚动的区域而不是包含他们的边框。

scroll

背景相对于元素本身固定,而不是随着它的内容滚动(对元素边框是有效的)。

对父元素 css_demo 设置 overflow: scroll, 当元素内容超出页面时滚动。 子元素 word 随着页面滚动显示, 对子元素 bg 设置 background-attachment: fixed, 使其在当前视口固定。

示例-1

预览

image-1-preview-min.gif

代码

代码语言:javascript
复制
<template>
  <div class="css_demo">
    <div class="word">视差滚动</div>
    <div class="bg bg1"></div>
    <div class="word">二</div>
    <div class="bg bg2"></div>
    <div class="word">三</div>
    <div class="bg bg3"></div>
    <div class="word">四</div>
    <div class="bg bg4"></div>
    <div class="word">五</div>
    <div class="bg bg5"></div>
    <div class="word">六</div>
    <div class="bg bg6"></div>
    <div class="word">七</div>
    <div class="bg bg7"></div>
  </div>
</template>
<style lang="scss" scoped>
.css_demo {
  width: 100%;
  // height: 100%;
  height: 100vh;
  overflow: scroll;
  .bg {
    background-position: center center;
    background-size: cover;
    background-attachment: fixed;
    &.bg1 {
      // 两种路径写法都可行, 只是后一种有路径提示, 浏览器最终为 background-image: url(/src/assets/images/1.jpeg);
      // background-image: url('/src/assets/images/1.jpeg');
      background-image: url('../assets/images/1.jpeg');
    }
    &.bg2 {
      background-image: url('/src/assets/images/2.jpeg');
    }
    &.bg3 {
      background-image: url('/src/assets/images/3.jpeg');
    }
    &.bg4 {
      background-image: url('/src/assets/images/4.jpeg');
    }
    &.bg5 {
      background-image: url('/src/assets/images/5.jpeg');
    }
    &.bg6 {
      background-image: url('/src/assets/images/6.jpeg');
    }
    &.bg7 {
      background-image: url('/src/assets/images/7.jpeg');
    }
  }
}
div {
  height: 100%;
  width: 100%;
  background: rgba(0, 0, 0, 0.1);
  color: #fff;
  line-height: 100vh;
  text-align: center;
  font-size: 20vh;
}
</style>

transform: translate3D

参考

原理详解

image-2023-7-20-13-50-51

我为 parallax 类的属性选择了 perspective 1px 的值,这意味着我们非常非常接近 div。

效果的速度由 和 translateZ() 提供 perspective 的值的组合控制。

减小 的值 translateZ() 会将元素推得更远,并且该元素的滚动速度会变慢。 该值离零越远,视差效应越明显。 translateZ(-5px) 滚动速度将比 translateZ(-1px) 慢 。

通过在不同速度滚动的元素层叠在一起,创建出一种立体感和深度感的效果。

transform 是一个属性,用于对元素进行变换(transformations) 它可以改变元素的位置(平移 translate)、大小(缩放 scale)、旋转角度(旋转 rotate) 和形状等

perspective 指定了观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果。 z>0 的三维元素比正常大,而 z<0 时则比正常小,大小程度由该属性的值决定。 元素涉及 3d 变换时,perspective可以让我们眼睛看到 3d 立体效果,有空间感。

transform-style 设置元素的子元素是位于 3D 空间中还是平面中。

通过设置transform-styleperspective,使该容器的子元素处在3D空间中, 然后设置transform: translateZ使物体在滚动的时候在Y轴移动位移不同,产生视觉差。

首先, 对于相同物体大小,相同位移速度, 就大小而言,近大远小, 而就物体位移速度而言,近快远慢 (看起来是这样而已)

由于 3D translations 模仿现实, 因此当我们在数字世界中移动物体时,也会有类似的物理效果。 例如,较远的东西(即 z 轴上的负平移)会移动得更慢。相反,距离较近的东西(即 z 轴上的正平移)会移动得更快。 另一个物理效应是规模。 如果我们把一些东西移得更远,它就会显得更小。如果它更近,它会显得更大。 如果你想抵消这种调整,你需要自己扩大或缩小它。

image-20230720145639107css3中的坐标系,rotateX就是绕着x轴旋转,rotateY就是绕着Y轴旋转,rotateZ就是绕着z轴旋转(也就是xy平面的旋转)。 perspective属性用来设置视点,在css3的模型中,视点是在Z轴所在方向上的。 translateX,translateY表现出在屏幕中的上下左右移动,transformZ 的直观表现形式就是大小变化, 实质是 XY平面相对于视点的远近变化(说远近就一定会说到离什么参照物远或近,在这里参照物就是perspective属性)。 比如设置了 perspective 为 200px; 那么 transformZ 的值越接近 200,就是离的越近,看上去也就越大,超过200就看不到了, 因为相当于跑到后脑勺去了,你不可能看到自己的后脑勺。 (200-transformZ的值)就是视点和xy平面的距离(初始是屏幕的位置,此时transformZ的值为0)。

perspective属性用在容器上时,容器内每个元素的表现形式会不一样。 当perspective属性用在容器内每个元素身上时,会根据各自的设置值进行表现。 打个比方就是你一个人平视盒子里的10个鸡蛋和十个你每人看1个一模一样鸡蛋。

image-2023-7-19-23-29-22

代码语言:javascript
复制
transform: translateZ(tz);

translateZ()函数可以在Z轴方向上移动元素。参数tz是一个 length 值,不能是百分比值。

正值会使元素沿Z轴正方向上移动,负值会使元素沿Z轴负方向上移动。

代码语言:javascript
复制
<style>
  .translated {
    transform: perspective(200px) translateZ(60px);
  }
</style>

<img src="images/1.gif" alt="Sample image"> 
<img class="translated" src="images/1.gif" alt="Sample image">

image-20230720140137480

代码语言:javascript
复制
<style>
  .translated {
	transform: perspective(200px) translateZ(-60px);
  }
</style>

<img src="images/1.gif" alt="Sample image"> 
<img class="translated" src="images/1.gif" alt="Sample image">

image-20230720140218162

代码语言:javascript
复制
div#myCircle {
  background-color: gray;
  width: 20px;
  height: 20px;
  border-radius: 100%;
  transform: translateX(11px) translateY(20px);
}

image-20230720140337542

image-20230720140400568

perspective ?

perspective() 函数用于定义 计算机屏幕平面应用 translateZ 属性的 HTMLElement 之间的虚拟距离。

这意味着 perspective(200px)translateZ(75px) 在HTMLElement和计算机屏幕之间创建了一个 200px 的虚拟空间, 并将其向你移动了 75px

代码语言:javascript
复制
div#myCircle {
  background-color: gray;
  width: 20px;
  height: 20px;
  border-radius: 100%;
  transform: translateX(11px) translateY(20px) translateZ(75px) perspective(200px);
}

image-20230720141338182

同样,使用负值在 translateZ() 中会将其移动得更远:

代码语言:javascript
复制
div#myCircle {
  background-color: gray;
  width: 20px;
  height: 20px;
  border-radius: 100%;
  transform: translateX(11px) translateY(20px) translateZ(-100px) perspective(200px);
}

image-20230720141649841

示例-1

预览

image-2023-7-20-15-05-40

向下滚动时,会发现就图片移动速度而言,图1 > 图2 > 图3, 这是因为这些图片离你的距离:图1 < 图2 < 图3, 图1 离你最近,因此随着你的滚动看起来最快,(注意:这里图片看起来没有近大远小,是因为手动放大了图片尺寸), 举个例子,你坐在行驶的车上,看路边风景,你会发现路边的树飞快的经过,而远处的山看起来就没多大变化, 更极端的是看夜空中的月亮,你会发现看起来他始终在那一个地方,无论怎么样。

代码

代码语言:javascript
复制
<template>
  <div class="parallax-container">
    <div class="parallax-layer layer1"></div>
    <div class="parallax-layer layer2"></div>
    <div class="parallax-layer layer3"></div>
  </div>
</template>
<style lang="scss" scoped>
.parallax-container {
  height: 100vh; /* 设置容器高度为视口高度 */
  overflow-x: hidden; /* 隐藏水平溢出内容 */
  overflow-y: auto; /* 允许垂直溢出内容 */
  perspective: 1px; /* 创建透视效果 */
}

.parallax-layer {
  height: 100vh; /* 设置每个层的高度为视口高度 */
  transform-style: preserve-3d; /* 保持 3D 变换效果 */
}

.layer1 {
  background-image: url('../assets/images/1.jpeg');
  background-size: cover;
  transform: translateZ(-1px) scale(2);
}

.layer2 {
  background-image: url('../assets/images/2.jpeg');
  background-size: cover;
  transform: translateZ(-2px) scale(1.5);
}

.layer3 {
  background-image: url('../assets/images/3.jpeg');
  background-size: cover;
  transform: translateZ(-3px) scale(1);
}
</style>

transform: translateZ(-2px) 是 CSS 变换属性的一种形式,用于在 3D 空间中沿 Z 轴方向进行平移。 在这个示例中,translateZ(-2px).layer2 层向内移动了 2 个像素单位。 通过在视差滚动中应用不同的 translateZ 值,可以创建层次感和深度效果。 较小的 translateZ 值会使层向内移动,产生更强烈的视差效果, 而较大的 translateZ 值会使层向外移动,产生较弱的视差效果。 在这个示例中,.layer2translateZ(-2px) 值比 .layer1translateZ(-1px) 值更大, 因此 .layer2 会在视差滚动中以较快的速度向内移动,产生更强烈的视差效果。 请注意,translateZ 值可以是负值,表示向内移动,也可以是正值,表示向外移动。 根据你的需求和设计,你可以调整 translateZ 值来实现不同的视差效果。

perspective: 1px; 是 CSS 属性,用于创建透视效果。 它定义了 观察者(即浏览器窗口)与 3D 元素之间的距离,从而影响到元素的透视效果。 透视效果是指当元素在 3D 空间中移动时,根据其与观察者的距离,产生的远近感和大小变化。 通过调整 perspective 属性的值,可以改变透视效果的强度。

在视差滚动中,"向内移动"和"向外移动"是相对于观察者(即浏览器窗口)的视角来说的。 当一个层的 translateZ 值为负时,它会向内移动,也就是朝向观察者的方向。 这样的移动会使层看起来更接近观察者,产生较强的视差效果。 在视差滚动中,这种效果可以让层看起来更大、更突出。 相反,当一个层的 translateZ 值为正时,它会向外移动,也就是远离观察者的方向。 这样的移动会使层看起来更远离观察者,产生较弱的视差效果。在视差滚动中,这种效果可以让层看起来较小、较平面。 在示例代码中,.layer1translateZ(-1px) 值比 .layer2translateZ(-2px) 值更小, 所以 .layer1 会以较慢的速度向内移动,而 .layer2 会以较快的速度向内移动。 这种差异会产生层次感和深度效果。

image-20230720151726923

其它示例

示例-1

预览

image-1-example-min.gif

代码

代码语言:javascript
复制
<template>
  <div class="exmaple">
    <div class="msg mg1">
      <div class="wd">SCREEN FIRST</div>
    </div>
    <div class="bd">Yes !</div>
    <div class="msg mg2">
      <div class="wd">SCREEN SECOND</div>
    </div>
    <div class="bd">No !</div>
    <div class="msg mg3">
      <div class="wd">SCREEN THIRD</div>
    </div>
    <div class="bd">Oh !</div>
    <div class="msg mg4">
      <div class="wd">SCREEN FOURTH</div>
    </div>
  </div>
</template>
<style lang="scss" scoped>
.exmaple {
  // 撑满 viewport 高度 (单屏)
  height: 100vh;
}
.msg {
  // 背景图片位置: 长度值: 背景图片左上角 相对于 背景图片所在元素左上角
  // 即 背景图片 左上角 与 容器左上角 对齐
  // 依次为 左右 上下
  background-position: 0 0;
  // 背景图片 相对于 viewport 固定
  background-attachment: fixed;
  // 背景图片尺寸: 铺满
  background-size: cover;
  height: 100%;
  width: 100%;
  &.mg1 {
    background-image: url('../assets/images/1.jpeg');
  }
  &.mg2 {
    background-image: url('../assets/images/2.jpeg');
  }
  &.mg3 {
    background-image: url('../assets/images/3.jpeg');
  }
  &.mg4 {
    background-image: url('../assets/images/4.jpeg');
  }
  .wd {
    position: relative;
    top: 480px;
    font-size: 55px;
    color: #fff;
    text-align: center;
    font-weight: bolder;
  }
}
.bd {
  text-align: center;
  font-size: 46px;
  font-weight: bolder;
  height: 220px;
  line-height: 220px;
  background-color: #ff7000;
  color: white;
}
</style>

解释

image-2023-7-19-17-33-13

虽然所有背景图都重叠在了视口处,但只有当其对应容器抵达视口时才能显示对应可视区域的背景图。 容器区域外无背景图。 背景图固定,但其背景图的呈现依然受所在容器元素区域限制,即背景图只能在容器区域显示,其余无背景图

Q&A

补充

CSS 初始化

参考:

100vh

参考:

viewport 视口/视窗 (屏幕可见部分(去除书签栏等, 真正用于渲染页面部分), 非整个浏览器窗口)

  • height:100% 铺满父容器的高度
  • height:100vh 铺满屏幕(viewport)的高度

"100vh" 是指大小为 "100" 单位为 "vh" 的一个相对 长度值。 vh 是 css 中的一个相对长度单位, 是相对于视窗的高度, 100vh 就是指 元素的高度等于当前浏览器的视窗高度, 即浏览器内部的可视区域的高度大小。 视窗被均分为 100 单位的 vh , 即1vh永远等于当前视窗高度的百分之一。 视窗被均分为 100 单位的 vh。 vh 优势在于能够直接获取高度, 而用 % 在没有设置 body 高度的情况下, 是无法正确获得可视区域的高度的。

100vh 在不同的浏览器的实现方式上也有一点微妙的变化, 这使得它几乎毫无用处。最好避免 100vh, 而是依赖 JavaScript 来设置高度,以获得完整的视口体验。

核心问题是移动浏览器(Chrome和Safari)有一个“帮助”功能,地址栏有时可见,有时隐藏,改变了视口的可见大小。 这些浏览器没有将 100vh 的高度调整为视口高度变化时屏幕的可见部分,而是将 100vh 设置为隐藏地址栏的浏览器高度。 结果是,当地址栏可见时,屏幕的底部部分将被切断,从而破坏了100vh的初衷。

如下所示:

当地址栏可见时,由于移动浏览器不正确地将100vh设置为屏幕高度而没有显示地址栏, 因此屏幕底部被切断。 在上图中,应该在屏幕底部的按钮被隐藏了。 更糟糕的是,当用户第一次使用手机访问网站时,地址栏会显示在页面顶部, 因此用户体验是很糟糕的。

一个好的解决方案: window.innerHeight

解决这个问题的一种方法是依赖 JavaScript 而不是 CSS。 当页面加载时,将高度设置为 window.innerHeight 将正确地将高度设置为窗口的可见部分。 如果地址栏是可见的,那么 window.innerHeight 是全屏的高度。 如果地址栏是隐藏的,那么 window.innerHeight 将是屏幕可见部分的高度, 正如您所期望的那样。

在 vue 项目中使用

${app}/src/App.vue

代码语言:javascript
复制
<script>
export default {
  name: 'App',
  mounted() {
    // First we get the viewport height and we multiple it by 1% to get a value for a vh unit
    let vh = window.innerHeight * 0.01
    // Then we set the value in the --vh custom property to the root of the document
    document.documentElement.style.setProperty('--vh', `${vh}px`)

    // We listen to the resize event
    window.addEventListener('resize', () => {
      // We execute the same script as before
      let vh = window.innerHeight * 0.01
      console.log(vh);
      document.documentElement.style.setProperty('--vh', `${vh}px`)
    })
  },
}
</script>

${app}/views/Foo.vue

代码语言:javascript
复制
<style lang="scss" scoped>
.container {
  height: 100vh; /* Fallback for browsers that do not support Custom Properties */
  height: calc(var(--vh, 1vh) * 100 - 46px);
</style>

在之前设置为 100vh,可以兼容某些不支持自定义属性的浏览器。

遗憾的是,仍然没有一种简单的方法可以让一个元素在不依赖javascript的情况下占据整个视口高度。 height: 100vh 是如此接近伟大,但考虑到它在移动设备上的局限性,最好避免它。

CSS: background

background-position

参考:

注意: 当两个值时, 依次为 background-position: 左右 上下;

而在 padding, margin 等中为 上右下左, 两个值时则为正对方向的值(缺省则正对方向), 即 上右 , 下=上, 左=右

代码语言:javascript
复制
padding:10px;                   /* 四个内边距都是10px */
padding:5px 10px;              /* 上下5px 左右10px */
padding:5px 10px 15px;          /* 上5px 右10px 下15px 左因为缺省与右相等,则为10px */
padding:5px 10px 15px 20px;     /* 上5px 右10px 下15px  左20px */

background-position: center;

百分比

给定背景图像位置的百分比偏移量是相对于 容器 的。 因此 50% 的值表示水平或垂直居中背景图像,因为图像的 50% 将位于容器的 50% 标记处。 类似的,background-position: 25% 75% 表示图像上的左侧 25% 和顶部 75% 的位置将放置在距容器左侧 25% 和距容器顶部 75% 的容器位置。

应用: CSS Sprite (雪碧图/精灵图)

参考:

雪碧图是根据 CSS sprite 音译过来的,就是将很多很多的小图标放在一张图片上,就称之为雪碧图。

使用雪碧图的目的: 有时为了美观,我们会使用一张图片来代替一些小图标, 但是一个网页可能有很多很多的小图标, 浏览器在显示页面的时候,就需要像服务器发送很多次访问请求,这样一来, 一是造成资源浪费, 二是会导致访问速度变慢。 这时候,把很多小图片(需要使用的小图标)放在一张图片上,按照一定的距离隔开, 就解决了上述的两个问题。

显示雪碧图的条件: 1. 一个设置好宽和高的容器 2. 设置 background-position 的值(默认为(0,0),也就是图片的左上角), 即移动图片到自己想要的图标位置 (UI 设计稿有标注)。

利用 background-position 对图标进行定位,若原来是 <img> 标签,替换成 <a><div><i><span>

例子

代码语言:javascript
复制
.search1 {
    background: url(../top/new_top_icons.png?20201205) no-repeat -344px 0;
    width: 16px;
    height: 16px;
    position: absolute;
    top: 10px;
    right: 10px;
}

height: 100%;

代码语言:javascript
复制
body, html {
  height: 100%;
}

.parallax {
  /* The image used */
  background-image: url("img_parallax.jpg");

  /* Full height */
  height: 100%;

  /* Create the parallax scrolling effect */
  background-attachment: fixed;
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-07-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • background-attachment
    • 示例-1
    • transform: translate3D
      • 原理详解
        • perspective ?
      • 示例-1
      • 其它示例
        • 示例-1
        • Q&A
        • 补充
          • CSS 初始化
            • 100vh
              • 一个好的解决方案: window.innerHeight
            • CSS: background
              • background-position
              • 应用: CSS Sprite (雪碧图/精灵图)
            • height: 100%;
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档