作者:米兰的小铁匠
来源:https://mp.weixin.qq.com/s/EG...
Hello,豆皮粉们,我来了,这回约稿又得到来自字节跳动的“米兰的小铁匠” ,几行CSS让你的页面立体起来,文章写的由浅入深,有实例代码可以学习😘。
先来看一个我们使用在产品中简单的例子:
这种类似翻扑克牌的动画完全通过 CSS 实现,而真正核心的部分只涉及到三个简单属性 perspective, transform, backface-visibility,在下面的文章部分,我会通过例子并逐步讲解清楚。
1. 普通的旋转
大家都知道,css3 的 transform 属性可以对元素进行视觉层面的形变操作,其中包含了旋转操作(Rotate):
@keyframes rotateX {
0% { transform: rotateX(0) }
100% { transform: rotateX(360deg) }
}
@keyframes rotateY {
0% { transform: rotateY(0) }
100% { transform: rotateY(360deg) }
}
@keyframes rotateZ {
0% { transform: rotateZ(0) }
100% { transform: rotateZ(360deg) }
}
.container {
.z-rotateX {
animation: rotateX 10s linear infinite;
}
.z-rotateY {
animation: rotateY 10s linear infinite;
}
.z-rotateZ {
animation: rotateZ 10s linear infinite;
}
}
不掉帧的演示和源码可以看这里: https://codepen.io/mongooseso...
这里分别演示了 RotateX、RotateY、RotateZ 旋转 360° 的动画效果,但是效果只是平面的,可能不太容易理解。在下面我们结合立体的动效来详细说明。
2. 立体的旋转
只添加了一行 CSS之 后的效果:
.container {
perspective: 800px;
// ......
}
不掉帧的演示和源码可以看这里: https://codepen.io/mongooseso...
其实,我们只添加了 perspective:800px 这一行代码。
那么 perspective 是什么意思呢?
官方的解释是:perspective 指定了观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果。
我们可以非常简单的理解为,从屏幕的视角出发,与3D元素容器的距离。perspective设置的越小,你看屏幕里的3D感觉越近,设置的越大,离得越远。当这个属性存在时,意味着该元素下所有子元素是立体的了。
默认情况下,是以元素的中心作为落脚点,可以理解为你是站在正视着元素的中心看的,如果你需要改变视角,可以使用 perspective-origin 这个属性。
3. 浏览器坐标系
有一个不得不提的问题的是,RotateX、Y、Z 到底是怎么旋转的?
浏览器的坐标系,水平向右是X轴正方向,竖直向下是Y轴正方向,垂直屏幕向外是Z轴正方向。
举个例子,transform: rotateX(45deg) 表示旋转中心为X轴,顺时针旋转45度。如果参数为负数,那就是逆时针旋转。
在识别的时候,我们可以使用左手规则,即左手大拇指指向对应轴的正方向,其他手指弯曲的方向就是顺时针方向。
为了便于理解,我找了两张图来说明
我们左手对着X轴正方向,手指弯曲的方向是朝向Y轴正方向,则可以推测,旋转45度的效果为:
友情提示:不要对着你的同事没事比划左手规则,如果比划的话,千万不要用Y轴方向的。如果你真的用了,请告诉我医院的 Wi-Fi 好不好。
所以上面动效使用的 RotateX,Y,Z 是不是都能理解了,同时 RotateZ 产生不了3D效果的原因也可以理解了吧。
4. 翻牌效果
像开篇提到的翻牌效果,又是如何实现的呢?
上面说到 perspective 是对子元素生效的,因此我们需要一个额外的 cards 容器,两个 div 分别表示正面和反面。
<div class="container">
<div class="cards">
<div class="card frontface" />
<div class="card backface" />
</div>
</div>
- 卡片公共属性
显而易见,卡片正反面都要指定 position: absolute,这样才能让卡片叠在一起。另外还需要指定,即本文的第二个重要属性 backface-visibility:hidden,这个属性非常好理解。
当一个元素指定 rotateY(180deg) 之后,根据左手规则,元素的正面朝里,背面对向我们,如果我们指定了此属性,即背向我们的元素我们不再需要可见。
.card {
position: absolute;
top: 0;
backface-visibility: hidden;
}
- 卡片正面
卡片正面不需要做任何特殊处理。
- 卡片背面
指定 transform: rotateY(180deg) 即可。
.backface {
transform: rotateY(180deg);
}
- cards块
显然,我们需要给cards块添加transition:transform属性以增加动画效果,另外我们还需要用上本文的第三个属性transform-style: preserve-3d。
这个属性值表示,这个元素下的所有的子元素处于3D空间中,存在着立体的层级和覆盖关系,如果你的容器元素内部有多个元素涉及到重叠的3D变换时,这个属性值是必须的。
.cards {
transition: transform 1s;
transform-style: preserve-3d;
}
container 块
最后,作为最外围容器,只需要设置 perspective 让子元素变为立体旋转,另外还需要设置 position: relative 让内部的absolute元素产生参照定位。.container { perspective: 800px; position: relative; }
一个简单的示例
详细的源码和Demo在这里: https://codepen.io/mongooseso...
5. 三维魔方
你可能发现过,webpack 官网的 logo 其实就是用 CSS 手写的,所以我们最后聊一下,怎么结合已有的属性,实现一个立方体的旋转。
先上完整代码和Demo: https://codepen.io/mongooseso...
HTML格式
同卡片效果类似,我们的HTML形式大致如下<div class="container"> <div class="cubes"> <div class="cube front" /> <div class="cube back" /> <div class="cube top" /> <div class="cube bottom" /> <div class="cube left" /> <div class="cube right" /> </div> </div>
父组件样式
和卡片一样,我们需要为外层的 cubes 容器和最外层的 container 容器设置3D视角属性.cubes { transform-style: preserve-3d; transition: transform 1s; width: 100%; height: 100%; } .container { position: relative; perspective: 400px; width: 200px; height: 200px; }
这里我们设置了正方体的边长为200px,以400px的视距来观察
- 绘制六个面
如果玩过魔方的同学可能知道,为了便于记录魔方的旋转,我们通常会给正方体六个面分别命名为前、后、左、右、上、下:
除了向前的那一面无须修改以外,其他面都可以认为是向前的一面做了各种旋转得出的结果
后:沿着Y轴顺时针旋转180deg
.back {
transform: rotateY(180deg)
}
左:沿着Y轴逆时针旋转90deg(可以好好思考下为什么是逆时针)
.left {
transform: rotateY(-90deg)
}
右:沿着Y轴顺时针旋转90deg
.right {
transform: rotateY(90deg)
}
上:沿着X轴顺时针旋转90deg
.top {
transform: rotateX(90deg)
}
下:沿着X轴逆时针旋转90deg
.bottom {
transform: rotateX(-90deg)
}
我们可以给不同的面标上背景色和花纹用来区分,此时这六个面还是互相交叉在一起的,我们还需要进行“位置”的调整
- 组合六个面
在 Demo 中,我们设置正方体的边长为200px,而这六个面交叉重叠的中心还是位于正方体的中心,因此我们需要通过给每个面设置 translateZ(100px) 即可让正方体位置调整正确,例如背面加上以后成为这样的样式
.back {
transform: rotateY(180deg) translateZ(100px);
}
- 绘制动效
接下来就简单了,我们可以给正方体绘制任何动效,感兴趣的甚至可以进一步绘制出如魔方的打乱和还原过程。
6. 实用场景
使用 CSS 来实现 3D 效果早就不是浏览器的新技术了,但是在实际产品中的应用仍然寥寥可数,适当的动效可以提升产品体验,相反复杂的动效会带来审美疲劳和开发负担。
WebGL 和 D3.js 等等确实是个好东西,但是他们的学习成本和开发成本都很高,需要付出不少的精力才能看到实际的回报,并且应用场景较少。
所以如果你想摆脱 2B 场景下枯燥的增删改查,2C场景下H5的枯燥交互,不妨大胆的使用下使用成本极低的 CSS 3D
The End
如果你觉得这篇文章对你有帮助,有启发,我想请你帮我2个小忙:
1、点个「赞」,让更多的人也能看到这篇文章内容;
2、关注公众号「豆皮范儿」,公众号后台回复「加群」 加入我们一起学习;
关注公众号的福利持续更新,公众号后台送学习资料:
1、公众号后台回复「vis」,还可以获取更多可视化免费学习资料。
2、公众号后台回复「webgl」,还可以获取webgl免费学习资料。
3、公众号后台回复「算法」,还可以获取算法的学习资料。
4、公众号后台回复「招聘」,获取各种内推。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。