首先声明一点,transform属性不为none的元素是它的定位子元素(绝对定位和固定定位)的包含块,而且对内创建一个新的层叠上下文。

注意:可以通过 transform-box 属性指定元素的那个盒子发生了变换,该属性的默认值是“border-box”,查MDN只有Firefox支持该属性(我试的没效果)。

CSS 3 中2D转换的实现用到两个属性:

属性 描述 CSS
transform 向元素应用 2D 或 3D 转换。 3
transform-origin 指定变换的基点的位置。 3

transform-origin

该属性实际上是指定局部坐标系的原点位置。

语法:

transform-origin: [ left | center | right | top | bottom | <percentage> | <length> ]
|
[ left | center | right | <percentage> | <length> ]
[ top | center | bottom | <percentage> | <length> ] <length>?
|
[ center | [ left | right ] ] && [ center | [ top | bottom ] ] <length>?

默认值为: 50%  50%  0;

不可继承。

值的计算都是以元素的border box为基准的,transform-origin的默认值把局部坐标系的原点移到了元素的中心。

注意:关于转换元素创建的局部坐标系,参见规范中的解释:local coordinate system

如果只指定了一个值,那么第二个值作为 "center" 处理;如果只指定了一个或两个值,第三个值作为 “0px”处理。

如果指定了两个或更多的值(三个)而且没有使用关键字类型的值,或者只使用了关键字“center”,那么第一个值代表距离border box左边界的距离,第二个值代表距离border box上边界的距离,第三个值代表在 z 轴方向上的位置(或位移),而且必须为长度值<length>。

关键字 解释
top 相当于垂直方向上的 0%
right 相当于水平方向上的 100%
bottom 相当于垂直方向上的 100%
left 相当于水平方向上的 0%
center

在垂直方向上相当于50%

或者在水平方向上相当于50%

MDN上对于可取值举的例子:

 /* 单值语法 */
transform-origin: 2px;
transform-origin: bottom; /* 双值语法 */
/* 用两个数字值先水平后垂直,用一个数值一关键字或两关键字不强求顺序 */
transform-origin: 3cm 2px; /* x-offset y-offset */
transform-origin: 2px left; /* y-offset x-offset-keyword */
transform-origin: left 2px; /* x-offset-keyword y-offset */
transform-origin: right top; /* x-offset-keyword y-offset-keyword */
transform-origin: top right; /* y-offset-keyword x-offset-keyword */ /* 三值语法 */
transform-origin: 2px 30% 10px; /* x-offset y-offset z-offset */
transform-origin: 2px left 10px; /* y-offset x-offset-keyword z-offset */
transform-origin: left 5px -3px; /* x-offset-keyword y-offset z-offset */
transform-origin: right bottom 2cm; /* x-offset-keyword y-offset-keyword z-offset */
transform-origin: bottom right 2cm; /* y-offset-keyword x-offset-keyword z-offset */

transform 2D转换

注意:

  1. 当对一个元素应用变换(2D 和 3D)时,连带着他的后代元素也应用了相同的变换。
  2. 应用了变换(2D 和 3D)的元素不会影响他周围元素的布局,其表现形式就像相对定位(position: relative)的元素的表现形式一样。也就是说,如果变换元素经过变换之后溢出了其父元素的边界,而其父元素的 overflow 属性又恰好是 scroll 或 auto,那么他的父元素就会产生滚动条,以便查看变换元素的溢出部分。

例子:

 <!DOCTYPE html>
<html>
<head>
<style>
.div1
{
position: relative;
height: 200px;
width: 200px;
margin: 100px;
padding:10px;
border: 1px solid black;
overflow: auto;
} .div2
{
padding:50px;
border: 1px solid black;
background-color: red;
transform: translate(100px) rotate(60deg) translate(100px,100px);
}
</style>
</head>
<body>
<div class="div1">
<div class="div2">HELLO
</div>
</div>
</body>
</html>)

效果:

transform属性用于2D转换的方法函数主要有以下几个。

转换方法 转换方式
translate() 平移
scale() 缩放
rotate() 旋转
skew() 倾斜
matrix() 矩阵变换

translate()

translate()函数指定元素的平移转换。他可接受两个参数,第一个参数表示沿 x 轴的平移量,第二个值表示沿 y 轴的平移量。如果只指定一个值,第二个值作为 0 处理。

另外还有只向一个方向平移的函数:

  • translateX()  该函数只接受一个参数,表示沿 x 轴的平移量。
  • translateY()  该函数只接受一个参数,表示沿 y 轴的平移量。

示例:

 <!DOCTYPE html>
<html>
<head>
<style>
#div3{
background-color: pink;
height: 250px;
width: 250px;
}
#div4{
height: 100px;
width: 100px;
background-color: gray;
transform: translate(100px,100px);
}
#div5{
height: 50px;
width: 50px;
background-color: yellow;
}
</style>
</head> <body>
<div id="div3">
<div id="div4" >
<div id="div5"></div>
</div>
</div>
</body>
</html>

效果:

从图中可以看出,作为子元素的黄色 div 也跟着平移了。

scale()

scale() 函数可以接受两个数字参数,表示缩放倍数。

第一个参数表示沿 x 轴的缩放,第二个值表示沿 y 轴缩放。小于 1,缩小;等于 1,大小不变;大于 1,放大。

如果只指定一个值,那么第二个值会被认为等于第一个值。

同样也有只沿一个方向缩放的函数:

  • scaleX()  该函数只接受一个参数,表示沿 x 轴缩放。相当于scale(tx, 1)。
  • scaleY()   该函数只接受一个参数,表示沿 y 轴缩放。相当于scale(1, ty)。

示例:

 <style>
#div3{
background-color: pink;
height: 200px;
width: 200px;
}
#div4{
height: 100px;
width: 100px;
background-color: gray;
transform: translate(50px,50px) scale(2);
}
#div5{
height: 50px;
width: 50px;
background-color: yellow;
}
</style> <body>
<div id="div3">
<div id="div4" >
<div id="div5"></div>
</div>
</div>
</body>

效果:

沿 x 轴和沿 y 轴的缩放距离是如何确定的呢?

具体要看基点在哪里,以上面的示例为例说明。

示例中粉色 div 是边长200px的正方形,灰色 div 是边长为100px的正方形,黄色 div 是边长50px的正方形,发生变换的是灰色 div。

灰色 div 变换的基点默认情况下在他的中心点。

以变换基点作局部坐标系,坐标轴的方向:x 轴向右为正;y 轴向下为正。此时在局部坐标系中,灰色 div 的边长被坐标原点均分到坐标轴的正负轴上,即正轴上的长度与负轴上的长度的比例为 1:1。当元素缩放变换时,就用局部坐标系中正负半轴上的部分边长分别乘以对应方向上的缩放倍数,用得到的值减去原来分布在半轴上的边长就得到元素应该在改半轴上扩展的距离。

示例中,灰色 div 分布在局部坐标系 x 轴正半轴上的边长为50px,那么50*2 = 100,100 - 50 = 50,所以灰色 div 沿局部坐标系 x 轴的正轴方向向外扩展50px,分布在其他半轴上的边长同理。最终结果就是灰色 div 恰好完全覆盖住粉色 div。

下面再举一个例子。

图中粉色 div 不考虑黑色边框时是边长为300px的正方形,灰色 div 是边长100px的正方形。如果灰色 div 的初始位置如图中所示,距离粉色 div 左侧和顶部分别为50px,那么灰色 div 仅仅通过缩放变换(需要改变变换基点的位置),要放大几倍能刚好覆盖粉色 div(不覆盖边框)?

这个问题可以通过前文介绍的缩放距离的计算方法计算出来,我的计算结果:

  1. 先把变换基点设置为 transform-origin: 25px 25px;
  2. 再用scale()函数放大 3 倍

代码:

 <style>
#div3{
position:relative;
background-color: pink;
height: 300px;
width: 300px;
border: 1px solid black;
}
#div4{
position: absolute;
top: 50px;
left: 50px;
height: 100px;
width: 100px;
background-color: gray;
transform-origin: 25px 25px;
transform: scale(3);
}
#div5{
height: 50px;
width: 50px;
background-color: yellow;
}
</style> <body>
<div id="div3">
<div id="div4" >
<div id="div5"></div>
</div>
</div>
</body>

效果:

另外,scale()函数还可以接受负值。

比如:

如果是scale(-1, 1),则转换后元素的位置与元素经scale(1, 1)变换后的位置关于局部坐标系的 y 轴的对称。

如果是scale(1, -1),则转换后元素的位置与元素经scale(1, 1)变换后的位置关于局部坐标系的 x 轴的对称。

如果是scale(-1, -1),则转换后元素的位置与元素经scale(1, 1)变换后的位置关于局部坐标系的原点(变换基点)中心对称。

示例:

代码还是前一例的代码。

scale(-3)变换与scale(3)变换的位置关于变换基点(25px, 25px)中心对称。

rotate()

rotate()函数通过指定的角度参数让元素进行2D旋转变换。

接受一个角度值,用来指定旋转的幅度。

如果这个值为正值,元素顺时针旋转;如果这个值为负值,元素逆时针旋转。

rotate()变换的元素绕着什么旋转呢?

其实是绕着局部坐标系(原点在变换基点)的 z 轴旋转。

示例:

 <style>
#div3{
position:relative;
background-color: pink;
height: 300px;
width: 300px;
border: 1px solid black;
margin: auto;
}
#div4{
position: absolute;
top: 50px;
left: 50px;
height: 100px;
width: 100px;
background-color: gray;
transform-origin: 25px 25px;
transform: rotate(-90deg);
}
#div5{
height: 50px;
width: 50px;
background-color: yellow;
}
</style> <body>
<div id="div3">
<div id="div4" >
<div id="div5"></div>
</div>
</div>
</body>

效果:

skew()

通过skew()函数,元素可以实现倾斜变换。

该函数可以接受两个参数(可以为负值),第一个参数表示元素的border box 的垂直边与参照坐标系 y 轴的夹角,第二个参数表示元素的border box 的水平边与参照坐标系 x 轴的夹角。

如果只指定了一个值,第二个值作为 0 处理。

另外也有只能指定一个夹角的函数:

  • skewX()  只接受一个参数,相当于skew()函数的第一个参数。
  • skewY()  只接受一个参数,相当于skew()函数的第二个参数。

示例:

 <style>

 /***********skew************/
#div6{
position:relative;
height: 300px;
width: 300px;
border: 1px solid black;
margin: auto;
}
#div7{
position:absolute;
top:75px;
left:75px;
height: 150px;
width: 150px;
background-color: #5555FF;
}
#div8{
position:absolute;
top:75px;
left:75px;
height: 150px;
width: 150px;
opacity: 0.7;
background-color: #66FF66;
}
</style> <body>
<!--skew-->
<div id="div6">
<div id="div7"></div>
<div id="div8"></div>
</div>
</body>

上面的代码的效果如下:

给 id="div8" 的元素添加以下CSS代码:

transform: skew(60deg);

或者

transform: skew(-120deg);

可以得到下图所示效果:

图中标出了局部坐标系及夹角。

matrix()

矩阵变换。

利用矩阵变换可以实现以上介绍的所有2D变换。也就是说,matrix()函数是以上几个函数的并集。

该函数可以接受6个参数,分别用a、b、c、d、e、f指代:

matrix(a, b, c, d, e, f);

这6个参数组成下面这个矩阵:

这就是 transform 的2D变换矩阵。

矩阵变换的原理:

x、y表示变换前元素上某一点在局部坐标系中的横纵坐标。

x' = ax + cy + e

y' = bx + dy + f

则 x'、y' 表示变换后元素上这一点在局部坐标系中的横纵坐标。

根据 x' 和 y' 的计算公式,只要给a、b、c、d、e、f指定不同的值就可以实现上述几种变换。

用matrix()实现平移变换

平移变换就是给原坐标分别加上我们指定的值。

举例,如果变换前元素中有一个点的坐标为(10px, 20px),经过 translate(20px, 5px) 的平移变换,则变换后该点的横坐标变为

10px + 20px = 30px

纵坐标变为

20px + 5px = 25px

即点(10px, 20px)平移到了点 (30px, 25px)。

根据 x' 的计算公式,让 a = 1,c = 0,e = 20,则 x' = 30;

根据 y' 的计算公式,让 b = 0,d = 1,f = 5,则 y' = 25;

所以 matrix(1, 0, 0, 1, 20, 5) 可以实现平移变换 translate(20px, 5px)。

其实,不管是什么样的平移变换,只要让 a = 1, b = 0,c = 0,d = 1,那么 e 就相当于translate()的第一个参数,f 就相当于translate()的第二个参数。

用matrix()实现缩放变换

缩放变换变换前的横纵坐标分别乘以指定的缩放倍数,从而得到变换后的横纵坐标。

举例,用matrix()实现scale(2,3)。

x' =  2x

y' = 3y

只要令 a = 2,c = 0,e = 0;b = 0,d = 3,f = 0 即可。即:

matrix(2, 0, 0, 3, 0, 0);

其实,不管是什么样的缩放变换,只要让 b = 0,c = 0,e = 0,f = 0,那么 a 就相当于scale()的第一个参数,d 就相当于scale()的第二个参数。

用matrix()实现旋转变换

如果有旋转变换rotate(θ),则 x' 、y' 的计算公式就变为:

x’ = x*cosθ - y*sinθ + 0 = x*cosθ - y*sinθ
y’ = x*sinθ + y*cosθ + 0 = x*sinθ + y*cosθ

也就是说

a = cosθ,c = - sinθ , e = 0

b = sinθ,d = cosθ,f = 0

matrix(cosθ, sinθ, -sinθ, cosθ, 0, 0);

用matrix()实现倾斜变换

如果有倾斜变换scale(θx, θy),则 x' 、y' 的计算公式就变为:

x’ = x + y*tanθx + 0 = x + y*tanθx
y’ = x*tanθy + y + 0 = x*tanθy + y

也就是说

a = 1,c = tanθx  , e = 0

b = tanθy,d = 1,f = 0

matrix(1, tanθy, tanθx, 1, 0, 0);

用matrix()实现简单镜像变换

这里说的简单镜像变换是指变换前的元素和变换后的元素关于经过局部坐标系原点的直线  y = kx 对称。

盗一张张大神的图:

关于参数的推到直接看张大神的文章,这里直接贴结果。

x' = (1-k*k) / (k*k+1) *x + 2k / (k*k+1) *y;
y' = 2k / (k*k+1) *x + (k*k-1) / (k*k+1) *y;

所以

a = (1-k*k) / (k*k+1)

b = 2k/(k*k+1)

c = 2k/(k*k+1)

d = (k*k-1)/(k*k+1)

e = 0

f = 0

(完)

参考资料

1、官方文档

2、CSS3 2D Transform

3、理解CSS3 transform中的Matrix(矩阵)

4、CSS3前端开发中需要用到的变换矩阵

CSS 3学习——transform 2D转换的更多相关文章

  1. CSS 3 学习——transform 3D转换渲染

    以下内容根据官方规范翻译,没有翻译关于SVG变换的内容和关于矩阵计算的内容. 一般情况下,元素在一个无景深无立体感的平面(flat plane)上渲染,这个平面就是其包含块所处的平面.同时,页面上的其 ...

  2. CSS新特性之2D转换transform

    transform是css3中具有颠覆性特征之一,可以实现元素的位移.旋转.缩放等效果 1.位移translate 1.1语法 transform: translate(x,y);//x,y分别表示x ...

  3. css 2D转换 transform-rotate 画插图

    学习了一点2D转换,关于Transfrom-rotate的小用法 rotate()方法,在一个给定度数顺时针旋转的元素.负值是允许的,这样是元素逆时针旋转. 下面看实例 第一个例子是没有使用rotat ...

  4. CSS3 Transform变形(2D转换)

    Transform:对元素进行变形:Transition:对元素某个属性或多个属性的变化,进行控制(时间等),类似flash的补间动画.但只有两个关键贞.开始,结束.Animation:对元素某个属性 ...

  5. css3学习笔记之2D转换

    translate() 方法 translate()方法,根据左(X轴)和顶部(Y轴)位置给定的参数,从当前元素位置移动. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...

  6. CSS中2d转换:transition过渡放在:hover伪类中与应用在整个元素中区别

    css的2d转换十分强大,能够在不使用js的情况下,实现页面的元素与用户之间更多动态的交互,增强用户体验.其中使用最多的就是hover伪类. 1.创建一个页面的div元素: <!DOCTYPE ...

  7. 2D转换下的zoom和transform:scale的区别

    一.什么是zoom 在我们做项目和查看别人的网页的时候总会在一些元素的样式里,看到有一个家伙孤零零的待在那里,它到底是谁呢? 它的名字叫zoom,zoom的意思是“变焦”,虽然在摄影的领域经常被提到, ...

  8. css 2D转换总结

    CSS中2D转换的形式是这样的: 选择器{ transform:转换函数(参数,参数): } 其中transform(是transform 不是transfrom)定义元素的2D或者3D转换: 2D转 ...

  9. CSS 2D转换

    转换是使元素改变形状.尺寸和位置的一种效果.通过 CSS3 转换,我们能够对元素进行移动.缩放.转动.拉长或拉伸,可以大致分为2D转换和3D转换.下面介绍的是2D转换的相关知识点. 首先,CSS中2D ...

随机推荐

  1. Storm如何保证可靠的消息处理

    作者:Jack47 PS:如果喜欢我写的文章,欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 本文主要翻译自Storm官方文档Guaranteeing messag ...

  2. C语言 · 4-3水仙花数

    问题描述 打印所有100至999之间的水仙花数.所谓水仙花数是指满足其各位数字立方和为该数字本身的整数,例如 153=1^3+5^3+3^3. 样例输入 一个满足题目要求的输入范例.例:无 样例输出 ...

  3. css3中perspective

    perspective 属性定义 3D 元素距视图的距离,以像素计.该属性允许改变 3D 元素查看 3D 元素的视图.当为元素定义 perspective 属性时,其子元素会获得透视效果,而不是元素本 ...

  4. Android数据加密之MD5加密

    前言: 项目中无论是密码的存储或者说判断文件是否是同一文件,都会用到MD5算法,今天来总结一下MD5加密算法. 什么是MD5加密? MD5英文全称“Message-Digest Algorithm 5 ...

  5. EntityFramework Core 1.1是如何创建DbContext实例的呢?

    前言 上一篇我们简单讲述了在EF Core1.1中如何进行迁移,本文我们来讲讲EF Core1.1中那些不为人知的事,细抠细节,从我做起. 显式创建DbContext实例 通过带OnConfiguri ...

  6. 做一个gulp+webpack+vue的单页应用开发架子

    1.目标 最近项目上的事情不多,根据我自己的开发习惯,决定开发一些简单的开发架子,方便以后事情多的时候直接套用.本文讲的一个gulp+webpack+vue的单页应用架子,想要达到的目的: 可以通过命 ...

  7. 年度巨献-WPF项目开发过程中WPF小知识点汇总(原创+摘抄)

    WPF中Style的使用 Styel在英文中解释为”样式“,在Web开发中,css为层叠样式表,自从.net3.0推出WPF以来,WPF也有样式一说,通过设置样式,使其WPF控件外观更加美化同时减少了 ...

  8. [原] KVM 虚拟化原理探究(5)— 网络IO虚拟化

    KVM 虚拟化原理探究(5)- 网络IO虚拟化 标签(空格分隔): KVM IO 虚拟化简介 前面的文章介绍了KVM的启动过程,CPU虚拟化,内存虚拟化原理.作为一个完整的风诺依曼计算机系统,必然有输 ...

  9. React Native 之 Text的使用

    前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...

  10. Java 教程整理:基础、项目全都有

    Java 在编程语言排行榜中一直位列前排,可知 Java 语言的受欢迎程度了. 网上有很多 Java 教程,无论是基础入门还是开发小项目的教程都比比皆是,可是系统的很少,对于Java 学习者来说找到系 ...