10

几行CSS让你的页面立体起来

 3 years ago
source link: https://zhuanlan.zhihu.com/p/339001102
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文转载自 豆皮范儿

豆皮范儿:几行CSS让你的页面立体起来 zhuanlan.zhihu.com r2E3QbE.jpg!mobile

Hello,豆皮粉们,我来了,这回约稿又得到来自字节跳动的“米兰的小铁匠” ,几行CSS让你的页面立体起来,文章写的由浅入深,有实例代码可以学习 。

amQ3Inf.gif!mobile

作者:米兰的小铁匠

来源:原创

先来看一个我们使用在产品中简单的例子:

qYryInb.gif!mobile

1. 普通的旋转

大家都知道,css3 的 transform 属性可以对元素进行视觉层面的形变操作,其中包含了旋转(Rotate):

R7NJvye.jpg!mobile2aQ7fq.gif!mobile

不掉帧的演示和源码可以看这里: https:// codepen.io/mongoosesong /pen/MWeyYjR

这里分别演示了 RotateX、RotateY、RotateZ 旋转 360° 的动画效果,但是效果只是平面的,可能不太容易理解。在下面我们结合立体的动效来详细说明。

2. 立体的旋转

mAZ3AzA.jpg!mobile

只添加了一行 CSS之 后的效果:

uEFfQf.gif!mobile

不掉帧的演示和源码可以看这里: https:// codepen.io/mongoosesong /pen/JjKXoyK

其实,我们只添加了 perspective:800px 这一行代码。

那么 perspective 是什么意思呢?

官方的解释是:perspective 指定了观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果。我们可以非常简单的理解为,从屏幕的视角出发,与3D元素容器的距离。perspective设置的越小,你看屏幕里的3D感觉越近,设置的越大,离得越远。当这个属性存在时,意味着该元素下所有子元素是立体的了。

默认情况下,是以元素的中心作为落脚点,可以理解为你是站在正视着元素的中心看的,如果你需要改变视角,可以使用 perspective-origin 这个属性。

3. 浏览器坐标系

有一个不得不提的问题的是,RotateX、Y、Z 到底是怎么旋转的?

浏览器的坐标系,水平向右是X轴正方向,竖直向下是Y轴正方向,垂直屏幕向外是Z轴正方向。

举个例子,transform: rotateX(45deg) 表示旋转中心为X轴,顺时针旋转45度。如果参数为负数,那就是逆时针旋转。

在识别的时候,我们可以使用左手规则,即左手大拇指指向对应轴的正方向,其他手指弯曲的方向就是顺时针方向。

为了便于理解,我找了两张图来说明

Z7Zvuiv.jpg!mobile

我们左手对着X轴正方向,手指弯曲的方向是朝向Y轴正方向,则可以推测,旋转45度的效果为:

F3qyUfZ.jpg!mobile

友情提示:不要对着你的同事没事比划左手规则,如果比划的话,千万不要用Y轴方向的。如果你真的用了,请告诉我医院的 Wi-Fi 好不好。

所以上面动效使用的 RotateX,Y,Z 是不是都能理解了,同时 RotateZ 产生不了3D效果的原因也可以理解了吧。

4. 翻牌效果

像开篇提到的翻牌效果,又是如何实现的呢?

上面说到 perspective 是对子元素生效的,因此我们需要一个额外的 container,两个 div 分别表示正面和反面。

73yAFzj.jpg!mobile
  • 卡片公共属性

显而易见,卡片正反面都要指定 position: absolute,这样才能让卡片叠在一起。另外还需要指定,即本文的第二个重要属性 backface-visibility:hidden,这个属性非常好理解。

当一个元素指定 rotateY(180deg) 之后,根据左手规则,元素的正面朝里,背面对向我们,如果我们指定了此属性,即背向我们的元素我们不再需要可见。

vUZbQv.jpg!mobile
  • 卡片正面

卡片正面不需要做任何特殊处理。

  • 卡片背面

指定 transform: rotateY(180deg) 即可。

vMzi6rb.jpg!mobile
  • cards块

显然,我们需要给cards块添加transition:transform属性以增加动画效果,另外我们还需要用上本文的第三个属性transform-style: preserve-3d。

这个属性值表示,这个元素下的所有的子元素处于3D空间中,存在着立体的层级和覆盖关系,如果你的容器元素内部有多个元素涉及到重叠的3D变换时,这个属性值是必须的。

yYRRB3j.jpg!mobile
  • container块

显然,我们需要给container块添加transition:transform属性以增加动画效果,另外我们还需要用上本文的第三个属性transform-style: preserve-3d。

InUzAnn.jpg!mobile

这个属性值表示,这个元素下的所有的子元素处于3D空间中,存在着立体的层级和覆盖关系,如果你的容器元素内部有多个元素涉及到重叠的3D变换时,这个属性值是必须的。

一个简单的示例

2MFfyyI.gif!mobile

源码和Demo在这里: https:// codepen.io/mongoosesong /pen/oNLxgpZ

5. 三维魔方

你可能发现过,webpack 官网的 logo 其实就是用 CSS 手写的,所以我们最后聊一下,怎么结合已有的属性,实现一个立方体的旋转。

F3qMruj.gif!mobile

先上Demo: https:// codepen.io/mongoosesong /pen/zYBqvwm

  • HTML格式

    同卡片效果类似,我们的HTML形式大致如下

j63Qnui.jpg!mobile
  • 父组件样式

和卡片一样,我们需要为外层的 cubes 容器和最外层的 container 容器设置3D视角属性

3Qv222b.jpg!mobile

这里我们设置了正方体的边长为200px,以400px的视距来观察

  • 绘制六个面

如果玩过魔方的同学可能知道,为了便于记录魔方的旋转,我们通常会给正方体六个面分别命名为前、后、左、右、上、下:

mYRR7ru.jpg!mobile

除了向前的那一面无须修改以外,其他面都可以认为是向前的一面做了各种旋转得出的结果

后:沿着Y轴顺时针旋转180deg

E7FnyeZ.jpg!mobile

左:沿着Y轴逆时针旋转90deg(可以好好思考下为什么是逆时针)

3eUry2R.jpg!mobile

右:沿着Y轴顺时针旋转90deg

veqInmB.jpg!mobile

上:沿着X轴顺时针旋转90deg

6zYnMb3.jpg!mobile

下:沿着X轴逆时针旋转90deg

FfUzuea.jpg!mobile

我们可以给不同的面标上背景色和花纹用来区分,此时这六个面还是互相交叉在一起的,我们还需要进行“位置”的调整

  • 组合六个面

在 Demo 中,我们设置正方体的边长为200px,而这六个面交叉重叠的中心还是位于正方体的中心,因此我们需要通过给每个面设置 translateZ(100px) 即可让正方体位置调整正确

aUV3meN.jpg!mobile
  • 绘制动效

接下来就简单了,我们可以给正方体绘制任何动效,感兴趣的甚至可以进一步绘制出如魔方的打乱和还原过程。

6. 实用场景

使用 CSS 来实现 3D 效果早就不是浏览器的新技术了,但是在实际产品中的应用仍然寥寥可数,适当的动效可以提升产品体验,相反复杂的动效会带来审美疲劳和开发负担。WebGL 和 D3.js 等等确实是个好东西,但是他们的学习成本和开发成本都很高,需要付出不少的精力才能看到实际的回报,并且应用场景较少。所以如果你想摆脱 2B 场景下枯燥的增删改查,2C场景下H5的枯燥交互,不妨大胆的使用下使用成本极低的 CSS 3D

vq2AJjV.gif!mobile

本文相关书籍:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK