2022-12-16
数据可视化
00

目录

前言
1. CSS3 Transform 介绍
1.1. 3D旋转
1.2. 3D透视
1.3. 3D位移
1.4. 3D缩放
1.5. 3D空间
2. 先实现一个正方形的骰子
3. 实现 Webpack logo
3.1 实现基本框架 v1 版本
3.2 绘制两个正方形
3.3 添加动画

前言

先直接展示下最终效果,想看代码的可以直接拉到最底部

4.gif

webpack 官网上的截图:

image.png

分析:webpack 这个 logo 的实现思路很简单,其实就是绘制了两个正方形,外面一个里面一个,然后让两个正方形按照不同的方向旋转即可

所以我们又可以把目标变成:如何实现一个正方形

css 中实现一个正方形,就不得不先讲一下 css3 transform

1. CSS3 Transform 介绍

CSS3 Transform 属性不但允许你进行 2D 的旋转,缩放或平移指定的元素,还支持 3D 变换元素。

常见的函数 transform function 有:

  • 平移:translate3d(tx, ty, tz)translateX(tx)translateY(ty)translateZ(tz)
  • 缩放:scale3d(sx, sy, sz)scaleX(sy)scaleY(sy)scaleZ(sz)
  • 旋转:rotate3d(x, y, z, a)rotateX(x)rotateY(y)rotateZ(z)

◼ 通过上面的几个函数,我们可以改变某个元素的 3D 形变。 ◼ 3D 形变函数会创建一个合成层来启用GPU硬件加速,比如: translate3dtranslateZscale3drotate3d ...

1.1. 3D旋转

1. rotateZ 、rotateX、rotateY

  • 旋转:rotateX(deg)rotateY(deg)rotateZ(deg)
    • CSS 函数定义一个变换,它将元素围绕固定轴旋转。旋转量由指定的角度确定; 为正,旋转将为顺时针,为负,则为逆时针。
  • 值个数
    • 只有一个值,表示旋转的角度(单位 deg
  • 值类型:
    • deg:<angle> 类型,表示旋转角度(不是弧度)。
    • 正数为顺时针
    • 负数为逆时针
  • 简写:rotate3d(x, y, z, deg)
  • 注意:旋转的原点受 transform-origin 影响

image.png

2. rotate3d

  • 旋转:rotate3d(x, y, z, a)
    • CSS 函数定义一个变换,它将元素围绕固定轴旋转。旋转量由指定的角度定义; 为正,运动将为顺时针,为负,则为逆时针。
  • 值个数
    • 一个值时,表示 z 轴 旋转的角度
    • 四个值时,表示在 3D 空间之中,旋转有 x , y , z 个旋转轴和一个旋转角度。
  • 值类型:
    • x:<number> 类型,可以是 0 到 1 之间的数值,表示旋转轴 X 坐标方向的矢量(用来计算形变矩阵中的值)。
    • y:<number> 类型,可以是 0 到 1 之间的数值,表示旋转轴 Y 坐标方向的矢量。
    • z:<number> 类型,可以是 0 到 1 之间的数值,表示旋转轴 Z 坐标方向的矢量。
    • a:<angle> 类型,表示旋转角度。正的角度值表示顺时针旋转,负值表示逆时针旋转。
  • 注意:旋转的原点受 transform-origin 影响

1.2. 3D透视

  • 透视:perspective
    • 定义了观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果(z 表示Z 轴)。
    • z>0 的三维元素比正常的大,而 z<0 时则比正常的小,大小程度由该属性的值决定。
  • 值个数
    • 只有一个值,表示观察者距离 z=0 的平面距离 和 none
  • 必须是 <none> <length> 中的一个
    • none:没有应用 perspective 样式时的默认值。
    • length:定观察者距离 z=0 平面的距离(如下图 d 的距离,单位 px)。 ✓ 为元素及其内容应用透视变换。当值为 0 或负值时,无透视变换。
  • 透视的两种使用方式:
    1. 在父元素上定义 CSS 透视属性
    2. 如果它是子元素或单元素子元素,可以使用函数 perspective()
  • 透视演练场:

image.png

1.3. 3D位移

1. translateX、translateY、translateZ

  • 平移:translateX(x)translateY(y)translateZ(z)
    • 该函数表示在二、三维平面上移动元素。
  • 值个数
    • 只有一个值,设置对应轴上的位移
  • 值类型:
    • 数字:100px
    • 百分比:参照元素本身( refer to the size of bounding box )

2. translate3d

平移:translate3d(tx, ty, tz)

  • CSS 函数在 3D 空间内移动一个元素的位置。这个移动由一个三维向量来表达,分别表示他在三个方向上移动的距离。
  • 值个数
    • 三个值时,表示在 3D 空间之中, tx , ty , tz 分别表示他在三个方向上移动的距离。
  • 值类型:
    • tx:是一个 <length> 代表移动向量的横坐标。
    • ty:是一个 <length> 代表移动向量的纵坐标。
    • tz:是一个 <length> 代表移动向量的 z 坐标。它不能是 <percentage> 值;那样的移动是没有意义的。
  • 注意:
    • translateX(tx)等同于 translate(tx, 0) 或者 translate3d(tx, 0, 0)
    • translateY(ty) 等同于 translate(0, ty) 或者 translate3d(0, ty, 0)
    • translateZ(zx) 等同于 translate3d(0, 0, tz)

1.4. 3D缩放

1. scaleX、scaleY、scaleZ

  • 缩放:scaleXscaleYscaleZ
    • 函数指定了一个沿 xyz 轴调整元素缩放比例因子。
  • 值个数
    • 一个值时,设置对应轴上的缩放(无单位)
  • 值类型:
    • 数字: ✓ 1:保持不变 ✓ 2:放大一倍 ✓ 0.5:缩小一半
    • 百分比:不支持百分比

2. scaleX、scaleY、scaleZ

  • 缩放:scale3d(sx, sy,sz)
    • CSS 函数定义了在 3D 空间中调整元素的缩放比例因子 。。
  • 值个数
    • 三个值时,表示在 3D 空间之中, sx, sy, sz 分别表示他在三个方向上缩放的向量。
  • 值类型:
    • sx:是一个 <number> 代表缩放向量的横坐标。
    • sy:是一个 <number> 表示缩放向量的纵坐标。
    • sz:是 <number> 表示缩放向量的 z 分量的 a(再讲到 3D 正方体再演示)。
  • 注意:
    • scaleX(sx) 等价于 scale(sx, 1)scale3d(sx, 1, 1)
    • scaleY(sy) 等价于 scale(1, sy)scale3d(1, sy, 1)
    • scaleZ(sz) 等价于 scale3d(1, 1, sz)

1.5. 3D空间

  • 变换式:transform-style
    • 该CSS属性用于设置元素的子元素是定位在 3D 空间中还是平展在元素的2D平面中。
    • 在3D空间中同样是可以使用透视效果。
  • 值类型:
    • flat:指示元素的子元素位于元素本身的平面内。
    • preserve-3d:指示元素的子元素应位于 3D 空间中。

image.png

  • 背面可见性:backface-visibility
    • 该CSS 属性 backface-visibility 指定某个元素当背面朝向观察者时是否可见。
  • 值类型:
    • visible:背面朝向用户时可见。
    • hidden:背面朝向用户时不可见。

image.png

2. 先实现一个正方形的骰子

先将骰子的六个面绘制出来,这里我用的 grid 布局,用 flex 也可以的

css
body { margin: 0; width: 100vw; height: 100vh; position: relative; } .dice-wrapper { position: relative; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 200px; height: 200px; display: flex; justify-content: space-around; align-items: center; } .dice-face { background-color: #fff; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 2px solid #000; border-radius: 10%; display: grid; place-items: center; grid-template: repeat(3, 1fr) / repeat(3, 1fr); grid-template-areas: "a . c" "e g f" "d . b"; } .dot { display: inline-block; width: 50%; height: 50%; border-radius: 50%; background-color: #000; } .dot:nth-child(2) { grid-area: b; } .dot:nth-child(3) { grid-area: c; } .dot:nth-child(4) { grid-area: d; } .dot:nth-child(5) { grid-area: e; } .dot:nth-child(6) { grid-area: f; } .dot:nth-child(odd):last-child { grid-area: g; }
html
<div class="dice-wrapper"> <div class="dice-face first-face"> <span class="dot"></span> </div> <div class="dice-face second-face"> <span class="dot"></span> <span class="dot"></span> </div> <div class="dice-face third-face"> <span class="dot"></span> <span class="dot"></span> <span class="dot"></span> </div> <div class="dice-face fourth-face"> <span class="dot"></span> <span class="dot"></span> <span class="dot"></span> <span class="dot"></span> </div> <div class="fifth-face dice-face"> <span class="dot"></span> <span class="dot"></span> <span class="dot"></span> <span class="dot"></span> <span class="dot"></span> </div> <div class="dice-face sixth-face"> <span class="dot"></span> <span class="dot"></span> <span class="dot"></span> <span class="dot"></span> <span class="dot"></span> <span class="dot"></span> </div> </div>

image.png

现在将 dice-wrapper 稍作修改:

/* 在父元素中添加 transform-style来启用3D空间 */ transform-style: preserve-3d; transform: rotateX(-33.5deg) rotateY(45deg);

此时六个面的效果都是这样的:

image.png

接下来我们一个个调整位置

第一个面

CSS
.first-face { transform: rotateX(90deg) translateZ(100px); }

image.png

第二个面

CSS
.second-face { transform: rotateX(-90deg) translateZ(100px); }

image.png

**第三个和第四个面 **

css
.third-face { transform: rotateY(0deg) translateZ(100px); } .fourth-face { transform: rotateY(-180deg) translateZ(100px); }

image.png

最后两个面

css
.fifth-face { transform: rotateY(-90deg) translateZ(100px); } .sixth-face { transform: rotateY(90deg) translateZ(100px); }

image.png

3. 实现 Webpack logo

有了上面实现正方形的基础,我们终于可以来实现这个 logo 啦。

3.1 实现基本框架 v1 版本

  1. css 部分
css
body { padding: 0; margin: 0; width: 100%; height: 100%; background-color: #2b3a42; display: flex; justify-content: center; align-items: center; } ul { margin: 0; padding: 0; list-style: none; } .webpack-logo { width: 100%; height: 200px; /* border: 1px solid red; */ position: relative; }
  1. html 部分
html
<div class="webpack-logo"> <!-- cube-inner --> <ul class="cube-inner"> <li class="top"></li> <li class="bottom"></li> <li class="front"></li> <li class="back"></li> <li class="left"></li> <li class="right"></li> </ul> <!-- cube-outer --> <ul class="cube-outer"> <li class="top"></li> <li class="bottom"></li> <li class="front"></li> <li class="back"></li> <li class="left"></li> <li class="right"></li> </ul> </div>

上面两部分都很简单:

  1. cube-inner 作为里面的正方
  2. cube-outer 作为外面的正方形。
  3. 两个正方形都有 top bottom front back left right 六个面

3.2 绘制两个正方形

根据第 2 节中的知识绘制两个正方形,要注意的是两个正方形的大小控制好两倍,我这里设置的是 50px 100px

添加 css

css
.cube-inner { position: absolute; left: 50%; top: 50%; /* 关键,不要用 transform */ margin: -25px 0px 0px -25px; width: 50px; height: 50px; /* background-color: red; */ /* 启用3D空间 */ transform-style: preserve-3d; transform: rotateX(-33.5deg) rotateY(45deg); /* 帧动画 */ animation: innerLoop 4s ease-in-out infinite; } .cube-inner li { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: #175d96; border: 1px solid white; } .cube-inner .top { transform: rotateX(90deg) translateZ(25px); } .cube-inner .bottom { transform: rotateX(-90deg) translateZ(25px); } .cube-inner .front { transform: rotateX(0deg) translateZ(25px); } .cube-inner .back { transform: rotateX(-180deg) translateZ(25px); } .cube-inner .left { transform: rotateY(-90deg) translateZ(25px); } .cube-inner .right { transform: rotateY(90deg) translateZ(25px); } /* cube outer */ .cube-outer { position: absolute; left: 50%; top: 50%; /* 关键,不要用 transform */ margin: -50px 0px 0px -50px; width: 100px; height: 100px; /* 启用3D空间 */ transform-style: preserve-3d; transform: rotateX(-33.5deg) rotateY(45deg); /* 帧动画 */ animation: outerLoop 4s ease-in-out infinite; } .cube-outer li { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(141, 214, 249, 0.5); border: 1px solid white; } .cube-outer .top { transform: rotateX(90deg) translateZ(50px); } .cube-outer .bottom { transform: rotateX(-90deg) translateZ(50px); } .cube-outer .front { transform: rotateX(0deg) translateZ(50px); } .cube-outer .back { transform: rotateX(-180deg) translateZ(50px); } .cube-outer .left { transform: rotateY(-90deg) translateZ(50px); } .cube-outer .right { transform: rotateY(90deg) translateZ(50px); }

3.3 添加动画

要让两个正方形转起来,可以使用 keyframes 帧动画

添加 css

css
@keyframes outerLoop { 0% { transform: rotateX(-33.5deg) rotateY(45deg); } 50%, 100% { transform: rotateX(-33.5deg) rotateY(405deg); } } @keyframes innerLoop { 0% { transform: rotateX(-33.5deg) rotateY(45deg); } 50%, 100% { transform: rotateX(-33.5deg) rotateY(-315deg); } }

OK,大功告成。

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:叶继伟

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!