前言
先直接展示下最终效果,想看代码的可以直接拉到最底部
webpack 官网上的截图:
分析: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硬件加速,比如: translate3d
、translateZ
、 scale3d
、 rotate3d
...
1.1. 3D旋转
1. rotateZ 、rotateX、rotateY
旋转:
rotateX(deg)
、rotateY(deg)
、rotateZ(deg)
- 该
CSS
函数定义一个变换,它将元素围绕固定轴旋转。旋转量由指定的角度确定; 为正,旋转将为顺时针,为负,则为逆时针。
- 该
值个数
- 只有一个值,表示旋转的角度(单位
deg
)
- 只有一个值,表示旋转的角度(单位
值类型:
- deg:
<angle>
类型,表示旋转角度(不是弧度)。 - 正数为顺时针
- 负数为逆时针
- deg:
- 简写:
rotate3d(x, y, z, deg)
- 注意:旋转的原点受
transform-origin
影响
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>
类型,表示旋转角度。正的角度值表示顺时针旋转,负值表示逆时针旋转。
- x:
- 注意:旋转的原点受
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
或负值时,无透视变换。- none:没有应用
透视的两种使用方式:
- 在父元素上定义
CSS
透视属性 - 如果它是子元素或单元素子元素,可以使用函数
perspective()
- 在父元素上定义
透视演练场:
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>
值;那样的移动是没有意义的。
- tx:是一个
注意:
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
缩放:
scaleX
、scaleY
、scaleZ
- 函数指定了一个沿
x
、y
、z
轴调整元素缩放比例因子。
- 函数指定了一个沿
值个数
- 一个值时,设置对应轴上的缩放(无单位)
值类型:
- 数字:
✓ 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
正方体再演示)。
- sx:是一个
注意:
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 空间中。
背面可见性:backface-visibility
- 该CSS 属性 backface-visibility 指定某个元素当背面朝向观察者时是否可见。
值类型:
- visible:背面朝向用户时可见。
- hidden:背面朝向用户时不可见。
2. 先实现一个正方形的骰子
先将骰子的六个面绘制出来,这里我用的 grid
布局,用 flex
也可以的
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;
}
<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>
现在将 dice-wrapper
稍作修改:
/* 在父元素中添加 transform-style来启用3D空间 */
transform-style: preserve-3d;
transform: rotateX(-33.5deg) rotateY(45deg);
此时六个面的效果都是这样的:
接下来我们一个个调整位置
第一个面
.first-face {
transform: rotateX(90deg) translateZ(100px);
}
第二个面
.second-face {
transform: rotateX(-90deg) translateZ(100px);
}
第三个和第四个面
.third-face {
transform: rotateY(0deg) translateZ(100px);
}
.fourth-face {
transform: rotateY(-180deg) translateZ(100px);
}
最后两个面
.fifth-face {
transform: rotateY(-90deg) translateZ(100px);
}
.sixth-face {
transform: rotateY(90deg) translateZ(100px);
}
3. 实现 Webpack logo
有了上面实现正方形的基础,我们终于可以来实现这个 logo
啦。
3.1 实现基本框架 v1 版本
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;
}
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>
上面两部分都很简单:
cube-inner
作为里面的正方cube-outer
作为外面的正方形。- 两个正方形都有
top
bottom
front
back
left
right
六个面
3.2 绘制两个正方形
根据第 2 节中的知识绘制两个正方形,要注意的是两个正方形的大小控制好两倍,我这里设置的是50px
100px
添加 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
@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,大功告成。