可视化 - css 3d形变

1,164 阅读11分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

数据可视化(英语:Data visualization),主要旨在借助于图形化手段,清晰有效地传达与沟通信息

为了清晰有效地传递信息,数据可视化通常使用柱状图、折线图、饼图、玫瑰图、散点图等图形来传递信息,也可以使用点、线、面、地图来对数字数据进行编码展示,以便在视觉上快速传达关键信息

可视化可以帮助用户分析和推理数据,让复杂的数据更容易理解和使用,有利于做出决策

常见可视化技术

  1. 底层图形引擎
引擎说明
skiachrome内置的图形绘制引擎
适合绘制2D和2.5D图形
是SVG和canvas在绘制的时候使用的图形引擎
openGL3D图形绘制引擎
  1. W3C提供:CSS3、Canvas、SVG、WebGL

  2. 第三方的可视化库: ZRender、Echarts、 AntV 、Highcharts、D3.js 、Three.js 和 百度地图、高德地图等等

    • ZRender - echarts的二维渲染引擎,本质上也是一个JS库
    • echarts绘制图形采用的是传入配置的方式
    • AntV和d3.js绘制图形采用的是使用JS调用库中所提供的API的方式
    • AntV是一系列功能可视化实现的集合
      • G2 - 2D 或 2.5D图表等
      • S2 - 专门用于在网页中展示各种格式的表格信息
      • G6 - 流程图,关系图等(主要用于展示,不可以交互)
      • L7 - 地理,地图等
      • X6(XFlow) - 面向React的可编辑,可交互的流程图,关系图等
  3. 低代码可视化平台:阿里云(DataV)、腾讯云图、网易有数(EasyScreen)、帆软等

transform

transform属性允许你旋转,缩放,倾斜或平移给定元素

常见的transform方法有:

  1. 平移: translate(x, y)
  2. 缩放: scale(x, y)
  3. 旋转: rotate(deg)
  4. 倾斜: skew(deg, deg)

通过上面的几个函数,我们就可以改变某个元素的2D形变

  1. transform不仅可以实现元素的2D形变,也可以对于该元素的3D形变

  2. transform属性的变换会以transform-origin作为整个形变坐标轴的原点

  3. 每执行一次transform,对应的元素坐标系就会相应的发送改变

    并且该元素所有后续变换都将基于新坐标系来执行相应的改变

    所以transform属性中变换函数的顺序非常重要,不同的顺序会导致不同的变换结果

坐标系

CSS 中的每个元素都有一个坐标系,其原点位于元素的左上角,左上角这被称为初始坐标系

方向说明
x轴水平向右右边是正方向,左边是负方向
y轴垂直向下下边是正方向,上边是负方向
z轴垂直于屏幕屏幕向外(朝向观察者)为正方向,往屏幕内部是负方向

image.png

使用用transform时,坐标系的原点默认会移动到元素的中心

image.png

因为transform-origin属性的默认值为50% 50%,即该原点将会作为变换元素的中心点

示例:

如果将一个元素绕 y 轴旋转 90 度,那么它的 x 轴将指向屏幕内部,即远离你

此时如再沿着 x 轴平移,元素不会向右移动,它会向内远离我们

transform-origin

transform-origin: 形变坐标系的原点 (默认为元素的左上角)

transform-origin移动的百分比相对的是自身元素宽度或高度

说明
一个值设置 x轴 的原点, y轴为默认值 50%
两个值设置 x轴 和 y轴 的原点
三个值设置 x轴、 y轴 和 z轴 的原点

可以设置的值为<length><percentage>,或 left, center, right, top, bottom关键字中的一个

关键字
left(0. 50%)
right(100%, 50%)
top(50%, 0)
bottom(100%, 50%)
let top(0, 0)
left bottom(0, 100%)
right top(100%, 0)
right bottom(100%, 100%)

3D transform

transform属性不但支持对元素进行2D形变,也支持对元素进行3D转换

3D形变函数会创建一个合成层来启用GPU硬件加速,从而提高渲染速度

旋转

3D旋转函数定义了一个变换,它将元素围绕固定轴旋转

旋转量由指定的角度确定 --- 为正,旋转将为顺时针,为负,则为逆时针

3D旋转效果受transform-origin影响

3D旋转函数,最终会生成一个4*4的矩阵

image.png

3D旋转函数有rotateX(deg)、rotateY(deg)、rotateZ(deg)

rotate3d(x, y, z, a)是这三个函数的简写形式

对于rotateX(deg)、rotateY(deg)、rotateZ(deg), 对应的参数值只有一个, 单位是角度(deg),不是弧度

对于 rotate3d(x, y, z, a), 参数有四个值

参数说明
x<number> 类型,可以是 0 到 1 之间的数值,表示旋转轴 X 坐标方向的矢量, 用来计算形变矩阵中的值
y<number> 类型,可以是 0 到 1 之间的数值,表示旋转轴 Y 坐标方向的矢量, 用来计算形变矩阵中的值
z<number> 类型,可以是 0 到 1 之间的数值,表示旋转轴 Z 坐标方向的矢量,用来计算形变矩阵中的值
a<angle> 类型,表示旋转角度。正的角度值表示顺时针旋转,负值表示逆时针旋转, 用来计算形变矩阵中的值
transform: rotate(45deg);

/* rotate(x)是rotateZ(x)的简写 */
transform: rotateZ(45deg);

/*
	rotateZ(x)是rotate3d(0, 0, 1, x)的2d写法
	虽然两者的效果是一致的,但是3d会开启一个独立的合成图层
	也就是说3d在渲染的时候会使用GPU硬件加速
*/
transform: rotate3d(0, 0, 1, 45deg);
/*
	rotateX, rotateY, rotateZ 并不会单独开辟一个新的渲染层
	rotate3d 会单独开辟一个新的渲染层
*/
transform: rotateX(50deg) /* 等同于 transform: rotate3d(1, 0, 0, 50deg);  */
transform: rotateY(50deg) /* 等同于 transform: rotate3d(0, 1, 0, 50deg);  */
transform: rotateZ(50deg) /* 等同于 transform: rotate3d(0, 0, 1, 50deg);  */

perspective

透视(perspective) 定义了观察者与 z = 0 平面的距离,使具有三维位置变换的元素产生透视效果(z表示Z轴)

z > 0 的三维元素比正常的大,而 z < 0 时则比正常的小,大小程度由该属性的值决定,也就是所谓的近大远小

perspective的值为<none> <length>中的一个

  • none: 没有应用 perspective 样式时的默认值
  • length: 设定观察者距离 z=0 平面的距离 (如下图d的距离,单位px)
    • 为元素及其内容应用透视变换。当值为 0 或负值时,无透视变换

image.png

当元素同时设置了透视和3D转换的时候,元素就可以产生3D效果

因为此时就可以存在近大远小的视觉效果,如果单单只是设置3D转换,不设置透视的话,只会单单以2D的形式产生对应的形变,并不会有直观的3D效果

透视的设置方式一 --- 在父元素上定义 CSS 透视属性

.container {
  /* 在父元素设置透视距离 */
  perspective: 400px;
}

.dv {
  transform: rotateY(45deg);
}

透视的设置方式二 --- 如果它是子元素或单元素子元素,可以使用函数 perspective()

.dv {
  /* 使用perpestive函数设置透视距离 */
  transform: perspective(400px) rotateY(45deg);
}

位移

translateX(x)、translateY(y)、translateZ(z)表示在二、三维平面上移动元素

参数值表示对应轴上的位移 单位可以是px或者百分比 (参照元素本身)

translate3d(tx, ty, tz)在 3D 空间内移动一个元素的位置。这个移动由一个三维向量来表达,分别表示他在三个方向上移动的距离

参数有三个值,分别表示在 3D 空间之中, tx, ty, tz 分别表示他在三个方向上移动的距离

参数说明
tx是一个<length> 代表移动向量的横坐标
ty是一个<length> 代表移动向量的纵坐标
tz是一个 <length> 代表移动向量的 z 坐标
tz不能是<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)
/* 元素放大 */
transform: perspective(300px) translateZ(100px);

/* 元素缩小 */
transform: perspective(300px) translateZ(-100px);

/* 位移值大于等于透视距离的时候,元素和视线相平或在视线后,所以看不见,表现为元素消失 */
transform: perspective(300px) translateZ(300px);

缩放

scaleX、scaleY、scaleZ指定了一个沿 x、y 、z轴调整元素缩放比例因子

scaleX、scaleY、scaleZ参数只有一个,表示对应轴上的缩放(无单位)

值是无单位的数字

  • 1: 保持不变
  • 2: 放大一倍
  • 0.5: 缩小一半

scale3d(sx, sy,sz) 定义了在 3D 空间中调整元素的缩放比例因子

参数有三个,分别表示在 3D 空间之中, sx, sy, sz 分别表示他在三个方向上缩放的向量

参数说明
sx是一个<number>代表缩放向量的横坐标
sy是一个<number>表示缩放向量的纵坐标
sz<number>表示缩放向量的 Z坐标
  • scale(sx, sy) 等价于 scaleX(sx), scaleY(sy)
  • scaleX(sx) 等价于scale(sx, 1) 或 scale3d(sx, 1, 1)
  • scaleY(sy)等价于 scale(1, sy) 或 scale3d(1, sy, 1)
  • scaleZ(sz)等价于 scale3d(1, 1, sz)

3D空间 - transform-style

transform-style可以控制是否给子元素开启3D空间

该属性是设置在要进行3d形变元素的父元素上,transform-style不是一个可继承属性

设置了transform-style的元素被称之为舞台或画布

transform-style往往结合perspective一起使用

属性值说明
flat默认值
元素的子元素位于元素本身的平面内
preserve-3d元素的子元素应位于 3D 空间

只进行3D转换,不开启透视,也不开启3D空间

.parent {
  width: 300px;
  height: 300px;
  background-color: red;
}

.child {
  width: 300px;
  height: 300px;
  background-color: skyblue;
  transform: rotateX(45deg);
}

image.png

开启3D转换和透视,不开启3D空间

.parent {
  width: 300px;
  height: 300px;
  background-color: red;
  perspective: 400px;
}

.child {
  width: 300px;
  height: 300px;
  background-color: skyblue;
  transform: rotateX(45deg);
}

image.png

开启3D转换和透视以及3D空间

.parent {
  width: 300px;
  height: 300px;
  background-color: red;
  transform-style: preserve-3d;
  perspective: 400px;
}

.child {
  width: 300px;
  height: 300px;
  background-color: skyblue;
  transform: rotateX(45deg);
}

image.png

3D背面可见性 - backface-visibility

backface-visibility 指定某个元素当背面朝向观察者时是否可见

说明
visible背面朝向用户时可见
默认值
当元素旋转角度大于90deg的时候,元素可见
hidden背面朝向用户时不可见
当元素旋转角度大于等于90deg的时候,元素不可见

backface-visibility的值无论是visible还是hidden

当元素旋转到90deg的时候,正好和页面是垂直的

所以此时这个元素就是不可见的

注意事项

浏览器渲染机制

  1. 解析HTML,构建DOM Tree

  2. 对CSS文件进行解析,解析出对应的规则树

  3. DOM Tree + CSSOM 生成 Render Tree

  4. 布局(Layout): 计算出每个节点的宽度、高度和位置信息

  5. 绘制(Paint): 将可见的元素绘制在屏幕中

默认标准流是在同一层上绘制,一些特殊属性会创建新的层绘制,这些层称为渲染层(render layout)

以下属性在渲染的时候会单独创建一个渲染层:

  1. 有明确的定位属性(relative、fixed、sticky、absolute)
  2. 透明度(opacity 小于 1)
  3. 有 CSS transform 属性(不为 none)
  4. 当前有对于 opacity、transform 应用动画
  5. backface-visibility 属性为 hidden

Composite合成层: 一些特殊属性会创建一个新的合成层( CompositingLayer ),并可以利用GPU来加速绘制

这是浏览器的 一种优化手段。合成层确实可以提高性能,但是它以消耗内存为代价,因此不能滥用作为 web 性能优化策略和过度使用

以下属性在渲染的时候会产生一个合成层:

  1. 对 opacity、transform应用了animation或transition,且是在动画执行中
  2. 开启了 3D transform 的元素
  3. video、canvas,iframe元素
  4. position: fixed
  5. will-change 设置为 opacity、transform、top、left、bottom、right
    • 比如: will-change: opacity , transform;
    • 其中 top、left等需要设置明确的定位属性,如 relative 等, 因为这样定位才会生效

示例

  1. 使用css形变实现一个立方体

  2. webpack logo的模拟实现

  3. 2.5D动画的实现