We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[TOC]
transform-origin
利用上面的变换函数,我们可以很简单的在2D、3D 维度上平移、缩放、旋转图像。
下面着重分析下两个让人迷惑却又揭示着变换属性本质的函数:matrix、matrix3d,允许使用者以矩阵的方式指定变换函数。
matrix
matrix3d
矩阵变换函数,相当于线性代数中的线性变换概念:线性变换T 中存在一个矩阵A,将一个向量x 变换为T(x),并记为:x→_A_x。简单理解为,将矩阵_A_ 点乘变换前的向量x 得到变换后的向量_T_(x),举个例子:
上面的例子使用的矩阵中的六个字母正是对应2D transfrom 中matrix 函数使用的六个数值。所有的2D 变换本质上均使用上面的矩阵_A_ 作线性转换。
注意了,上面提到了一个概念:线性转换,简单理解为,线性转换与非线性转换的区别在于,矩阵_A_ 能否转换整个子空间。即,给定矩阵_A_ 和转换后的子空间,是否 中的每个变量_T_(x) 在转换前的子空间中都对应的变量。
将上面的例子转换为线性代数中的参数方程组来理解线性转换的意思:
在上述参数方程组中,对于任一 组合,方程组均有解。
那么问题来了,既然是2D 转换,使用2x2 矩阵应该就刚好将 子空间转换啦,为什么要使用3x3 矩阵,上面矩阵中,第三行[0 0 1]像没什么用?
其实不然,2x2 的矩阵是无法完成2D 维度的线性平移变换(translate、translateX、translateY)的。具体的证明请参见线性代数的相关章节。于是,我们需要站在更高的维度上完成线性平移变换,也就是引入齐次坐标(也是线性代数的概念)。使用方式是,在2D 变换中,为方便计算,一般会将 中每个点对应与中的,也就是位于平面上方1 单位的平面上,我们称有齐次坐标。
齐次坐标的意义在于,矩阵与向量点乘时引入与向量坐标无关的常量,常量往往就是平移的值,而2D 变换的齐次坐标经过运算后,z 轴的值是不需要改变的,所以,矩阵的最后一行只能为[0 0 1]。
其实,齐次方程的思想我们从小就有接触,那就是二元一次方程,比如:,该方程可以视为1D 变换,以矩阵变换的方式相当于:
正如上文所说,matrix属性是所有变换函数的本质,在半桶水地引入了上面这么多线代的知识后,终于要写我想表达的:来尝试用matrix属性代替其他的2D 变换函数。
形如transform: translate(e,f);的样式可以转为:transform: matrix(1,0,0,1,e,f);。对应矩阵如下:
transform: translate(e,f);
transform: matrix(1,0,0,1,e,f);
形如transform:scale(a,d);的样式可以转为:transform: matrix(a,0,0,d,0,0);。对应矩阵如下:
transform:scale(a,d);
transform: matrix(a,0,0,d,0,0);
形如transform: rotate(𝒂deg);的样式可以转为:transform: matrix(cos𝒂,sin𝒂,-sin𝒂,cos𝒂);。对应矩阵如下:
transform: rotate(𝒂deg);
transform: matrix(cos𝒂,sin𝒂,-sin𝒂,cos𝒂);
矩阵的推导过程参考:推导坐标旋转公式
形如transform: skew(𝒂deg,𝒃deg);的样式可以转为:transform: matrix(1,tan𝒃,tan𝒂,1,0,0);。对应矩阵如下:
transform: skew(𝒂deg,𝒃deg);
transform: matrix(1,tan𝒃,tan𝒂,1,0,0);
理解完2D 的变换矩阵再来看3D 变换矩阵就简单很多了,无非就是在3x3 的矩阵上引入齐次坐标变成4x4 的矩阵,对应的,matrix3d()函数支持16 个参数,与2D 变换矩阵不一样的是,3D 变换矩阵的最后一行不再是一成不变的[0 0 0 1],而是支持透视投影样式:perspective(下文会详细解释)。4x4 矩阵变换表示如下:
matrix3d()
在支持的3D 变换函数中,重点关注下rotate3d(x,y,z,𝒂deg)与matrix3d()的转换。
rotate3d(x,y,z,𝒂deg)
以向量(m, n, o) 为轴旋转𝒂 度的样式为:transform:rotate3d(m,n,o,𝒂deg);,对应矩阵如下:
transform:rotate3d(m,n,o,𝒂deg);
其中:
在我们了解了上面的基本变换与矩阵的转换之后,其实,我们还能做得更多。
在上手编写变换的效果时,我可以预想得到,至少会有两种情境:
针对第一种情况,我们可以尽量拆分变换步骤,以达到每个步骤都值做很基本的变换效果,比如平移、缩放、旋转等,由于transform属性值支持多变换函数,于是,我们可以把每个步骤对应的变换函数值以列表形式传给transform属性。
transform
例一:我想要做一个2D 变换:图像沿x 轴平移20px,然后旋转45度,然后x 坐标放大2 倍,y 轴倾斜30 度。
想完成这样一个变换,编写的变换函数是:
transform: translateX(20px) rotate(45deg) scaleX(2) skewY(30deg);
类似上面变换函数与矩阵的转换,这里我们会使用矩阵点乘来进行矩阵转换:
矩阵点乘的结果如下:
针对第二种情况,我们利用线性变换矩阵_A_与单位矩阵有_I_ 存在的关系来求解:A I = A,即线性变换矩阵与单位矩阵的点乘等于线性矩阵本身,以2D 变换矩阵为例:
这个关系带来的启发是,只要我们知道变换前单位矩阵各列坐标在变换后的坐标位置,然后将变换后的坐标以矩阵形式写出来,就等于我们相求的矩阵_A_ 了。
css 中的transform属性的定义是具有继承性质的,也就是,父元素的变换会导致后代元素进行同样的变换,这是很容易理解的,否则会出现比如父元素平移了20px,如果后代元素不继承,就会出现父子脱离的现象,显然是不合理的。
transform属性不为none的元素会创建一个独立的坐标系来完成声明的变换,若元素的父元素也有不为none 的transform属性定义,则子元素的坐标系会在父元素坐标系的基础上创建。若元素的transform属性定义了多个变换,则每个变换都会根据自身需要调整子元素当前的坐标系。举个例子:
none
.box { transform: skewX(20deg); } .box > .son { transform: skewY(30deg) skewX(-45deg); }
.box
.son
skewY
skewX
最终结果:.son元素的transform属性创建的坐标轴跟父元素的坐标轴相比,多了两次转换。
原始的CSS 变换坐标系大概以下图所示呈现:
即X 轴水平向右,Y 轴垂直向下,Z 轴垂直屏幕坐在平面指向用户。该坐标轴为左手坐标系。
CSS 变换的目的是转换坐标,而坐标的值是建立在坐标系上的,自然,坐标系的原点相对图像的位置也会影响最终的转换效果,这个在rotate类型的变换中尤其明显。可以想象,图像以左上角旋转和以右下角旋转的到的图像是不一样的。CSS 变换默认是以图像中心点作为原点进行的,要更改原点位置,可以使用transform-origin属性。举个例子:
rotate
.box1 { height: 100px; width: 100px; transform-origin: 50px 50px; transform: rotate(45deg); } .box2 { height: 100px; width: 100px; transform-origin: bottom left; transform: rotate(45deg); }
.box1中的指定的transform-origin位于图像中点,与默认行为一致。.box2则将图像旋转的原点设为了左下角。
.box1
.box2
现在对transform-origin这个属性有了个直观感受了:图像变换坐标系的原点,那接下来,继续探讨下,CSS 在计算变换函数矩阵时是如何实现(兼顾)自定义原点位置的,以2D 变换为例:
transform-origin:(tx, ty)
translate(tx, ty)
translate(-tx, -ty)
详细的图像描述参考:
上图中黑色的点就是原点的位置,左侧的图展示了上述的第一步,原点偏移,中间的图展示了第二步,元素执行transform 变换,右侧的图展示了原点针对transform-origin的逆偏移。
以矩阵运算的角度看上面4 个步骤:
perspective属性是控制3D 变换Z 轴纵深视感(也就是立体感)的关键属性。
perspective
在接触3D 变换之前,元素几乎都是渲染在一个只有X 轴、Y 轴的平面上(先不考虑z-index),而html 文档中的所有元素都共享着这么一个平面。但当引入3D 变换后,元素的渲染我们就可以站在三维空间的角度去看了。也就是,除却X 轴、Y 轴坐标,元素中点还拥有了各自不同的Z 轴坐标。
z-index
日常生活中,同样的一个物体,离观察者远则显小,离观察者近则显大,而我们觉得这个物体有立体感,正是因为它不是平面的,而是有些部位离我们近,有些部位离我们远。
同样的,在CSS 渲染三维空间的元素时,默认它是不知道观察者的位置的,此时,我们看到的渲染结果是没有立体感的,仿佛整个三维空间都被一束平行光投射到二维平面上了。举个例子:
<style> div { height: 150px; width: 150px; } .container { border: 1px solid black; background-color: gray; } .transformed { transform: rotateY(50deg); background-color: blue; } </style> <div class="container"> <div class="transformed"></div> </div>
上面这段样式渲染结果如下:
可以看到,蓝色的矩形围绕Y 轴旋转了50 度,但整个图像看起来跟二维平面是一样的,只是直观看上去,这个矩形变小了。那为什么变小了,道理也很简单,Y 轴是平面垂直向下的,元素坐标系原点默认在中心,然后整个元素围绕Y 轴旋转50 度,元素中心Z 值为0,向左Z 值越大,向右Z 值越小。然后,一束垂直屏幕所在平面的平行光将元素投射到Z 为0 的平面上,于是,元素看起来就像变小了一样。
于是,为了让三维空间的元素渲染出立体感,我们需要告诉CSS,观察者的位置,也就是给出观察者距离屏幕有多远。当CSS 确定观察者位置后,渲染元素时,Z 轴坐标越大(越靠近观察者),元素越大,Z 轴坐标越小(越远离观察者),元素越小。
使用perspective属性即可指定观察者的位置,举个例子:
<style> div { height: 150px; width: 150px; } .container { perspective: 500px; border: 1px solid black; background-color: gray; } .transformed { transform: rotateY(50deg); background-color: blue; } </style> <div class="container"> <div class="transformed"></div> </div>
有了perspective的声明,通过放大中心点左侧的部分(Z 轴坐标相对大)、缩小中心点右侧的部分(Z 轴坐标相对小),终于营造出rotateY带来立体感了。
rotateY
花了这么多口水终于说完perspective的作用,接下来,我们从数学关系上探讨这个属性到底是怎样影响元素大小的。一图胜千语:
图中d表示perspective设定的观察者距离屏幕的长度,Z表示元素的Z 轴坐标,虚线圆表示元素的原始大小,
d
Z
蓝色背景圆表示元素实际的现实大小。可以看到,当元素的Z 轴坐标大于0,则实际渲染的要比原始的大,当元素的Z 轴坐标小于0,则实际渲染的要比原始的小。
假设元素原始大小为,经过perspective转换之后大小为,则有:。
当,,有。当,,有。
perspective属性的声明有两种用法,一种是在父元素声明,一种是在当前元素的transform列表的开头声明。
除了指定观察者的距离,我们还可以使用perspective-origin:(tx, ty)属性指定观察者的视角。
perspective-origin:(tx, ty)
我们可以把观察者所在地方看作一个平面,默认的视角到屏幕的连线与屏幕成90 度角,perspective-origin指定视角的平移值,类似于translate。再来看一图:
perspective-origin
translate
perspective、perspective-origin最终作为一个矩阵参与到整个变换,矩阵计算过程如下:
perspective对应的矩阵为:
上面4 步得出的矩阵变换算式是:
上述的矩阵进行完运算后,会得到一个4x4 的矩阵,使用该矩阵对元素坐标进行变换,则元素的每个坐标会被转换为类似:(x, y, z, w),若有指定perspective,w 会等于。而齐次坐标的值在变换前后是不能改变的,所以,最终元素的坐标等于:(x/w, y/w, z/w, 1)。
(x, y, z, w)
(x/w, y/w, z/w, 1)
实际渲染时,CSS 对元素4 个角的坐标值,对应d、Z 的不同大小关系会做不同处理:
(xn, yn, zn, 1)
3D render context (3D 渲染上下文)影响3D 变换是否会出现元素交错的现象。
当带有3D 变换函数的函数在非3D 渲染上下文中渲染时,并不会改变该元素的显示顺序,而是按正常的渲染步骤来走,在html 文档结构中,靠前的元素先显示,靠后的元素后显示,当元素位置出现重叠时,靠后的元素会覆盖靠前的元素。即使元素3D 变换让它有了比较大的Z 轴坐标,也只能让它在显示上可能变大而已。
而3D 渲染上下文的显示规则也很简单,Z 轴坐标越大,则显示越靠近用户,Z 轴坐标越小,则显示越远离用户,并允许不同Z 轴坐标的元素间出现交错的渲染,元素交错的渲染算法使用Newell's algorithm。
下面的规则描述了元素是如何创建以及加入到3D 渲染上下文的:
transform-style: preserve-3d
在上面的规则中,我们使用了transform-style属性来标识元素是否需要创建或扩展3D 渲染上下文。该属性有两个可选值:
transform-style
当一个元素处于3D 渲染上下文时,其变换的矩阵计算过程如下:
矩阵的计算过程中,有两点需要注意:
fixed
absolute
relative
当一个元素进行3D 变换时,就会有正面和背面的分别,backface-visibility属性用于控制元素背面是否可见,该属性只能用于进行3D 变换的元素。
backface-visibility
可选值有两个:
当transform属性参与到CSS 动画(animate)或过渡(transition)时,变换函数列表需要使用插值法(Interpolation)计算得出。参照以下四条规则来计算动画期间的函数列表:
The text was updated successfully, but these errors were encountered:
No branches or pull requests
[TOC]
"transform" 属性
2D Transform
transform-origin
指定点(默认是中心点)旋转𝚊 度,单位为deg;3D Transform
利用上面的变换函数,我们可以很简单的在2D、3D 维度上平移、缩放、旋转图像。
下面着重分析下两个让人迷惑却又揭示着变换属性本质的函数:
matrix
、matrix3d
,允许使用者以矩阵的方式指定变换函数。矩阵变换函数,相当于线性代数中的线性变换概念:线性变换T 中存在一个矩阵A,将一个向量x 变换为T(x),并记为:x→_A_x。简单理解为,将矩阵_A_ 点乘变换前的向量x 得到变换后的向量_T_(x),举个例子:
上面的例子使用的矩阵中的六个字母正是对应2D transfrom 中matrix 函数使用的六个数值。所有的2D 变换本质上均使用上面的矩阵_A_ 作线性转换。
注意了,上面提到了一个概念:线性转换,简单理解为,线性转换与非线性转换的区别在于,矩阵_A_ 能否转换整个子空间。即,给定矩阵_A_ 和转换后的子空间,是否 中的每个变量_T_(x) 在转换前的子空间中都对应的变量。
将上面的例子转换为线性代数中的参数方程组来理解线性转换的意思:
在上述参数方程组中,对于任一 组合,方程组均有解。
那么问题来了,既然是2D 转换,使用2x2 矩阵应该就刚好将 子空间转换啦,为什么要使用3x3 矩阵,上面矩阵中,第三行[0 0 1]像没什么用?
其实不然,2x2 的矩阵是无法完成2D 维度的线性平移变换(translate、translateX、translateY)的。具体的证明请参见线性代数的相关章节。于是,我们需要站在更高的维度上完成线性平移变换,也就是引入齐次坐标(也是线性代数的概念)。使用方式是,在2D 变换中,为方便计算,一般会将 中每个点对应与中的,也就是位于平面上方1 单位的平面上,我们称有齐次坐标。
齐次坐标的意义在于,矩阵与向量点乘时引入与向量坐标无关的常量,常量往往就是平移的值,而2D 变换的齐次坐标经过运算后,z 轴的值是不需要改变的,所以,矩阵的最后一行只能为[0 0 1]。
其实,齐次方程的思想我们从小就有接触,那就是二元一次方程,比如:,该方程可以视为1D 变换,以矩阵变换的方式相当于:
矩阵与变换
正如上文所说,
matrix
属性是所有变换函数的本质,在半桶水地引入了上面这么多线代的知识后,终于要写我想表达的:来尝试用matrix
属性代替其他的2D 变换函数。translate 变换
形如
transform: translate(e,f);
的样式可以转为:transform: matrix(1,0,0,1,e,f);
。对应矩阵如下:scale 变换
形如
transform:scale(a,d);
的样式可以转为:transform: matrix(a,0,0,d,0,0);
。对应矩阵如下:rotate 变换
形如
transform: rotate(𝒂deg);
的样式可以转为:transform: matrix(cos𝒂,sin𝒂,-sin𝒂,cos𝒂);
。对应矩阵如下:矩阵的推导过程参考:推导坐标旋转公式
skew 变换
形如
transform: skew(𝒂deg,𝒃deg);
的样式可以转为:transform: matrix(1,tan𝒃,tan𝒂,1,0,0);
。对应矩阵如下:理解完2D 的变换矩阵再来看3D 变换矩阵就简单很多了,无非就是在3x3 的矩阵上引入齐次坐标变成4x4 的矩阵,对应的,
matrix3d()
函数支持16 个参数,与2D 变换矩阵不一样的是,3D 变换矩阵的最后一行不再是一成不变的[0 0 0 1],而是支持透视投影样式:perspective(下文会详细解释)。4x4 矩阵变换表示如下:在支持的3D 变换函数中,重点关注下
rotate3d(x,y,z,𝒂deg)
与matrix3d()
的转换。rotate3d 变换
以向量(m, n, o) 为轴旋转𝒂 度的样式为:
transform:rotate3d(m,n,o,𝒂deg);
,对应矩阵如下:其中:
在我们了解了上面的基本变换与矩阵的转换之后,其实,我们还能做得更多。
在上手编写变换的效果时,我可以预想得到,至少会有两种情境:
针对第一种情况,我们可以尽量拆分变换步骤,以达到每个步骤都值做很基本的变换效果,比如平移、缩放、旋转等,由于
transform
属性值支持多变换函数,于是,我们可以把每个步骤对应的变换函数值以列表形式传给transform
属性。例一:我想要做一个2D 变换:图像沿x 轴平移20px,然后旋转45度,然后x 坐标放大2 倍,y 轴倾斜30 度。
想完成这样一个变换,编写的变换函数是:
类似上面变换函数与矩阵的转换,这里我们会使用矩阵点乘来进行矩阵转换:
矩阵点乘的结果如下:
针对第二种情况,我们利用线性变换矩阵_A_与单位矩阵有_I_ 存在的关系来求解:A I = A,即线性变换矩阵与单位矩阵的点乘等于线性矩阵本身,以2D 变换矩阵为例:
这个关系带来的启发是,只要我们知道变换前单位矩阵各列坐标在变换后的坐标位置,然后将变换后的坐标以矩阵形式写出来,就等于我们相求的矩阵_A_ 了。
变换函数与坐标系
css 中的
transform
属性的定义是具有继承性质的,也就是,父元素的变换会导致后代元素进行同样的变换,这是很容易理解的,否则会出现比如父元素平移了20px,如果后代元素不继承,就会出现父子脱离的现象,显然是不合理的。transform
属性不为none
的元素会创建一个独立的坐标系来完成声明的变换,若元素的父元素也有不为none
的transform
属性定义,则子元素的坐标系会在父元素坐标系的基础上创建。若元素的transform
属性定义了多个变换,则每个变换都会根据自身需要调整子元素当前的坐标系。举个例子:.box
元素的transform
属性创建了一个新的坐标系,然后使X 轴顺时针旋转20度来完成自身指定变换;.box
进行变换的同时,子类元素.son
也进行了一样的变换,此时.son
的坐标系与父元素的坐标系一样;.son
自身也有定义变换函数,而且还定义了两个:skewY
变换,该变换使.son
坐标系的Y 轴顺时针旋转了30度;skewX
变换,该变换使.son
坐标系的X 轴逆时针旋转了45 度。最终结果:
.son
元素的transform
属性创建的坐标轴跟父元素的坐标轴相比,多了两次转换。原始的CSS 变换坐标系大概以下图所示呈现:
即X 轴水平向右,Y 轴垂直向下,Z 轴垂直屏幕坐在平面指向用户。该坐标轴为左手坐标系。
"transform-origin" 属性
CSS 变换的目的是转换坐标,而坐标的值是建立在坐标系上的,自然,坐标系的原点相对图像的位置也会影响最终的转换效果,这个在
rotate
类型的变换中尤其明显。可以想象,图像以左上角旋转和以右下角旋转的到的图像是不一样的。CSS 变换默认是以图像中心点作为原点进行的,要更改原点位置,可以使用transform-origin
属性。举个例子:.box1
中的指定的transform-origin
位于图像中点,与默认行为一致。.box2
则将图像旋转的原点设为了左下角。transform 变换矩阵计算总结
现在对
transform-origin
这个属性有了个直观感受了:图像变换坐标系的原点,那接下来,继续探讨下,CSS 在计算变换函数矩阵时是如何实现(兼顾)自定义原点位置的,以2D 变换为例:transform-origin:(tx, ty)
属性,则将该属性的值转换为相对元素左上角位置的偏移距离,得到偏移距离后,元素所在坐标系的原点按该偏移距离做一次translate(tx, ty)
;transform
属性指定的变换函数;transform-origin
变换的操作,也就是将第一步中做的偏移给回退,即最后做了一次translate(-tx, -ty)
;详细的图像描述参考:
上图中黑色的点就是原点的位置,左侧的图展示了上述的第一步,原点偏移,中间的图展示了第二步,元素执行
transform
变换,右侧的图展示了原点针对transform-origin
的逆偏移。以矩阵运算的角度看上面4 个步骤:
"perspective" & "perspective-origin"属性
perspective
属性是控制3D 变换Z 轴纵深视感(也就是立体感)的关键属性。在接触3D 变换之前,元素几乎都是渲染在一个只有X 轴、Y 轴的平面上(先不考虑
z-index
),而html 文档中的所有元素都共享着这么一个平面。但当引入3D 变换后,元素的渲染我们就可以站在三维空间的角度去看了。也就是,除却X 轴、Y 轴坐标,元素中点还拥有了各自不同的Z 轴坐标。日常生活中,同样的一个物体,离观察者远则显小,离观察者近则显大,而我们觉得这个物体有立体感,正是因为它不是平面的,而是有些部位离我们近,有些部位离我们远。
同样的,在CSS 渲染三维空间的元素时,默认它是不知道观察者的位置的,此时,我们看到的渲染结果是没有立体感的,仿佛整个三维空间都被一束平行光投射到二维平面上了。举个例子:
上面这段样式渲染结果如下:
可以看到,蓝色的矩形围绕Y 轴旋转了50 度,但整个图像看起来跟二维平面是一样的,只是直观看上去,这个矩形变小了。那为什么变小了,道理也很简单,Y 轴是平面垂直向下的,元素坐标系原点默认在中心,然后整个元素围绕Y 轴旋转50 度,元素中心Z 值为0,向左Z 值越大,向右Z 值越小。然后,一束垂直屏幕所在平面的平行光将元素投射到Z 为0 的平面上,于是,元素看起来就像变小了一样。
于是,为了让三维空间的元素渲染出立体感,我们需要告诉CSS,观察者的位置,也就是给出观察者距离屏幕有多远。当CSS 确定观察者位置后,渲染元素时,Z 轴坐标越大(越靠近观察者),元素越大,Z 轴坐标越小(越远离观察者),元素越小。
使用
perspective
属性即可指定观察者的位置,举个例子:上面这段样式渲染结果如下:
有了
perspective
的声明,通过放大中心点左侧的部分(Z 轴坐标相对大)、缩小中心点右侧的部分(Z 轴坐标相对小),终于营造出rotateY
带来立体感了。花了这么多口水终于说完
perspective
的作用,接下来,我们从数学关系上探讨这个属性到底是怎样影响元素大小的。一图胜千语:图中
d
表示perspective
设定的观察者距离屏幕的长度,Z
表示元素的Z 轴坐标,虚线圆表示元素的原始大小,蓝色背景圆表示元素实际的现实大小。可以看到,当元素的Z 轴坐标大于0,则实际渲染的要比原始的大,当元素的Z 轴坐标小于0,则实际渲染的要比原始的小。
假设元素原始大小为,经过
perspective
转换之后大小为,则有:。当,,有。当,,有。
perspective
属性的声明有两种用法,一种是在父元素声明,一种是在当前元素的transform
列表的开头声明。除了指定观察者的距离,我们还可以使用
perspective-origin:(tx, ty)
属性指定观察者的视角。我们可以把观察者所在地方看作一个平面,默认的视角到屏幕的连线与屏幕成90 度角,
perspective-origin
指定视角的平移值,类似于translate
。再来看一图:perspective 矩阵计算总结
perspective
、perspective-origin
最终作为一个矩阵参与到整个变换,矩阵计算过程如下:perspective-origin
的计算值做平移(translate);perspective
对应的矩阵;perspective-origin
的逆平移;perspective
对应的矩阵为:上面4 步得出的矩阵变换算式是:
上述的矩阵进行完运算后,会得到一个4x4 的矩阵,使用该矩阵对元素坐标进行变换,则元素的每个坐标会被转换为类似:
(x, y, z, w)
,若有指定perspective
,w 会等于。而齐次坐标的值在变换前后是不能改变的,所以,最终元素的坐标等于:(x/w, y/w, z/w, 1)
。实际渲染时,CSS 对元素4 个角的坐标值,对应d、Z 的不同大小关系会做不同处理:
(xn, yn, zn, 1)
,其中n 无限大;3D render context & "transform-style" 属性
3D render context (3D 渲染上下文)影响3D 变换是否会出现元素交错的现象。
当带有3D 变换函数的函数在非3D 渲染上下文中渲染时,并不会改变该元素的显示顺序,而是按正常的渲染步骤来走,在html 文档结构中,靠前的元素先显示,靠后的元素后显示,当元素位置出现重叠时,靠后的元素会覆盖靠前的元素。即使元素3D 变换让它有了比较大的Z 轴坐标,也只能让它在显示上可能变大而已。
而3D 渲染上下文的显示规则也很简单,Z 轴坐标越大,则显示越靠近用户,Z 轴坐标越小,则显示越远离用户,并允许不同Z 轴坐标的元素间出现交错的渲染,元素交错的渲染算法使用Newell's algorithm。
下面的规则描述了元素是如何创建以及加入到3D 渲染上下文的:
transform-style: preserve-3d
且自身不在3D 渲染上下文时,则会新建一个3D 渲染上下文,同时,元素自身也会加入到这个上下文中;transform-style: preserve-3d
,也不会创建新的,而是共享并扩展该上下文;在上面的规则中,我们使用了
transform-style
属性来标识元素是否需要创建或扩展3D 渲染上下文。该属性有两个可选值:3D render context 矩阵计算总结
当一个元素处于3D 渲染上下文时,其变换的矩阵计算过程如下:
perspective
矩阵;transform
变换矩阵;transform
变换矩阵;矩阵的计算过程中,有两点需要注意:
transform
变换前的平面都是一个独立的CSS 视觉格式化模型( visual formatting model) ,意思是,子元素如果使用fixed
、absolute
、relative
定位,则原点都是元素的左上角,不会是屏幕左上角或祖先元素的左上角;"backface-visibility" 属性
当一个元素进行3D 变换时,就会有正面和背面的分别,
backface-visibility
属性用于控制元素背面是否可见,该属性只能用于进行3D 变换的元素。可选值有两个:
Interpolation of Transform
当
transform
属性参与到CSS 动画(animate)或过渡(transition)时,变换函数列表需要使用插值法(Interpolation)计算得出。参照以下四条规则来计算动画期间的函数列表:none
,则没有插值计算的需要,保持none
即可;none
,则会将none
转化为一个个单位矩阵来对应transform
中每个变换函数;transform
的变换函数列表计算为一个矩阵,然后应用矩阵插值法;参考文献
The text was updated successfully, but these errors were encountered: