首先声明一点,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. 总结:Mac前端开发环境的搭建(配置)

    新年新气象,在2016年的第一天,我入手了人生中第一台自己的电脑(大一时好友赠送的电脑在一次无意中烧坏了主板,此后便不断借用别人的或者网站的).macbook air,身上已无分文...接下来半年的房 ...

  2. NodeJs之OS

    OS Node.js提供了一些基本的底层操作系统的模块OS. API var os = require('os'); console.log('[arch] 操作系统CPU架构'+os.arch()) ...

  3. 从I/O复用谈epoll为什么高效

    上一篇文章中,谈了一些网络编程的基本概念.在现实使用中,用的最多的就是I/O复用了,无非就是select,poll,epoll 很多人提到网络就说epoll,认为epoll效率是最高的.单纯的这么认为 ...

  4. ASP.NET Aries 入门开发教程4:查询区的下拉配置

    背景: 今天去深圳溜达了一天,刚回来,看到首页都是微软大法好,看来离.NET的春天就差3个月了~~ 回到正题,这篇的教程讲解下拉配置. 查询区的下拉配置: 1:查询框怎么配置成下拉? 在配置表头:格式 ...

  5. TODO:Laravel增加验证码

    TODO:Laravel增加验证码1. 先聊聊验证码是什么,有什么作用?验证码(CAPTCHA)是"Completely Automated Public Turing test to te ...

  6. 旺财速啃H5框架之Bootstrap(二)

    突然感觉不知道写啥子,脑子里面没水了,可能是因为今晚要出去浪,哈哈~~~提前提醒大家平安夜要回家哦,圣诞节生00000000000这么多蛋....继续 上一篇的已经把bootstrap了解个大概了,接 ...

  7. 菜鸟Python学习笔记第二天:关于Python黑客。

    2016年1月5日 星期四 天气:还好 一直不知道自己为什么要去学Python,其实Python能做到的Java都可以做到,Python有的有点Java也有,而且Java还是必修课,可是就是不愿意去学 ...

  8. Node.js学习笔记——Node.js开发Web后台服务

    一.简介 Node.js 是一个基于Google Chrome V8 引擎的 JavaScript 运行环境.Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效.Node.j ...

  9. Atitit 解决Unhandled event loop exception错误的办法

    Atitit 解决Unhandled event loop exception错误的办法 查看workspace/.metadata/.log org.eclipse.swt.SWTError: No ...

  10. atitit.attilax的软件 架构 理念.docx

    atitit.attilax的软件 架构 理念.docx 1. 预先规划.1 2. 全体系化1 3. 跨平台2 4. 跨语言2 5. Dsl化2 5.1. 界面ui h5化2 6. 跨架构化2 7. ...