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

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

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

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

transform-origin

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

语法:

  1. transform-origin: [ left | center | right | top | bottom | <percentage> | <length> ]
  2. |
  3. [ left | center | right | <percentage> | <length> ]
  4. [ top | center | bottom | <percentage> | <length> ] <length>?
  5. |
  6. [ 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上对于可取值举的例子:

  1. /* 单值语法 */
  2. transform-origin: 2px;
  3. transform-origin: bottom;
  4.  
  5. /* 双值语法 */
  6. /* 用两个数字值先水平后垂直,用一个数值一关键字或两关键字不强求顺序 */
  7. transform-origin: 3cm 2px; /* x-offset y-offset */
  8. transform-origin: 2px left; /* y-offset x-offset-keyword */
  9. transform-origin: left 2px; /* x-offset-keyword y-offset */
  10. transform-origin: right top; /* x-offset-keyword y-offset-keyword */
  11. transform-origin: top right; /* y-offset-keyword x-offset-keyword */
  12.  
  13. /* 三值语法 */
  14. transform-origin: 2px 30% 10px; /* x-offset y-offset z-offset */
  15. transform-origin: 2px left 10px; /* y-offset x-offset-keyword z-offset */
  16. transform-origin: left 5px -3px; /* x-offset-keyword y-offset z-offset */
  17. transform-origin: right bottom 2cm; /* x-offset-keyword y-offset-keyword z-offset */
  18. 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,那么他的父元素就会产生滚动条,以便查看变换元素的溢出部分。

例子:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <style>
  5. .div1
  6. {
  7. position: relative;
  8. height: 200px;
  9. width: 200px;
  10. margin: 100px;
  11. padding:10px;
  12. border: 1px solid black;
  13. overflow: auto;
  14. }
  15.  
  16. .div2
  17. {
  18. padding:50px;
  19. border: 1px solid black;
  20. background-color: red;
  21. transform: translate(100px) rotate(60deg) translate(100px,100px);
  22. }
  23. </style>
  24. </head>
  25. <body>
  26. <div class="div1">
  27. <div class="div2">HELLO
  28. </div>
  29. </div>
  30. </body>
  31. </html>

效果:

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

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

translate()

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

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

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

示例:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <style>
  5. #div3{
  6. background-color: pink;
  7. height: 250px;
  8. width: 250px;
  9. }
  10. #div4{
  11. height: 100px;
  12. width: 100px;
  13. background-color: gray;
  14. transform: translate(100px,100px);
  15. }
  16. #div5{
  17. height: 50px;
  18. width: 50px;
  19. background-color: yellow;
  20. }
  21. </style>
  22. </head>
  23.  
  24. <body>
  25. <div id="div3">
  26. <div id="div4" >
  27. <div id="div5"></div>
  28. </div>
  29. </div>
  30. </body>
  31. </html>

效果:

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

scale()

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

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

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

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

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

示例:

  1. <style>
  2. #div3{
  3. background-color: pink;
  4. height: 200px;
  5. width: 200px;
  6. }
  7. #div4{
  8. height: 100px;
  9. width: 100px;
  10. background-color: gray;
  11. transform: translate(50px,50px) scale(2);
  12. }
  13. #div5{
  14. height: 50px;
  15. width: 50px;
  16. background-color: yellow;
  17. }
  18. </style>
  19.  
  20. <body>
  21. <div id="div3">
  22. <div id="div4" >
  23. <div id="div5"></div>
  24. </div>
  25. </div>
  26. </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 倍

代码:

  1. <style>
  2. #div3{
  3. position:relative;
  4. background-color: pink;
  5. height: 300px;
  6. width: 300px;
  7. border: 1px solid black;
  8. }
  9. #div4{
  10. position: absolute;
  11. top: 50px;
  12. left: 50px;
  13. height: 100px;
  14. width: 100px;
  15. background-color: gray;
  16. transform-origin: 25px 25px;
  17. transform: scale(3);
  18. }
  19. #div5{
  20. height: 50px;
  21. width: 50px;
  22. background-color: yellow;
  23. }
  24. </style>
  25.  
  26. <body>
  27. <div id="div3">
  28. <div id="div4" >
  29. <div id="div5"></div>
  30. </div>
  31. </div>
  32. </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 轴旋转。

示例:

  1. <style>
  2. #div3{
  3. position:relative;
  4. background-color: pink;
  5. height: 300px;
  6. width: 300px;
  7. border: 1px solid black;
  8. margin: auto;
  9. }
  10. #div4{
  11. position: absolute;
  12. top: 50px;
  13. left: 50px;
  14. height: 100px;
  15. width: 100px;
  16. background-color: gray;
  17. transform-origin: 25px 25px;
  18. transform: rotate(-90deg);
  19. }
  20. #div5{
  21. height: 50px;
  22. width: 50px;
  23. background-color: yellow;
  24. }
  25. </style>
  26.  
  27. <body>
  28. <div id="div3">
  29. <div id="div4" >
  30. <div id="div5"></div>
  31. </div>
  32. </div>
  33. </body>

效果:

skew()

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

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

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

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

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

示例:

  1. <style>
  2.  
  3. /***********skew************/
  4. #div6{
  5. position:relative;
  6. height: 300px;
  7. width: 300px;
  8. border: 1px solid black;
  9. margin: auto;
  10. }
  11. #div7{
  12. position:absolute;
  13. top:75px;
  14. left:75px;
  15. height: 150px;
  16. width: 150px;
  17. background-color: #5555FF;
  18. }
  19. #div8{
  20. position:absolute;
  21. top:75px;
  22. left:75px;
  23. height: 150px;
  24. width: 150px;
  25. opacity: 0.7;
  26. background-color: #66FF66;
  27. }
  28. </style>
  29.  
  30. <body>
  31. <!--skew-->
  32. <div id="div6">
  33. <div id="div7"></div>
  34. <div id="div8"></div>
  35. </div>
  36. </body>

上面的代码的效果如下:

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

  1. transform: skew(60deg);

或者

  1. transform: skew(-120deg);

可以得到下图所示效果:

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

matrix()

矩阵变换。

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

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

  1. 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 即可。即:

  1. 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

  1. 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

  1. 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. 从源码看Azkaban作业流下发过程

    上一篇零散地罗列了看源码时记录的一些类的信息,这篇完整介绍一个作业流在Azkaban中的执行过程,希望可以帮助刚刚接手Azkaban相关工作的开发.测试. 一.Azkaban简介 Azkaban作为开 ...

  2. 谈谈一些有趣的CSS题目(三)-- 层叠顺序与堆栈上下文知多少

    开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...

  3. .NET 基础 一步步 一幕幕[面向对象之方法、方法的重载、方法的重写、方法的递归]

    方法.方法的重载.方法的重写.方法的递归 方法: 将一堆代码进行重用的一种机制. 语法: [访问修饰符] 返回类型 <方法名>(参数列表){ 方法主体: } 返回值类型:如果不需要写返回值 ...

  4. macOS 我的装机

    最近多次配置 Mac 的开发环境,稍微记录一下 1 创建无付费信息的Apple ID 2 Xcode ​ gem 源更改 3 Alfred 4 微信 5 SourceTree 6 Sublime Te ...

  5. document.documentElement.clientHeight 与 document.body.clientHeight(杜绝千篇一律的抄袭!!)

    document.documentElement.clientHeight 与 document.body.clientHeight用来获取页面可视高度我觉得有点问题.这两个应该不是一个东西. 页面中 ...

  6. 简析服务端通过GT导入SHP至PG的方法

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 项目中需要在浏览器端直接上传SHP后服务端进行数据的自动入PG ...

  7. Javacript实现字典结构

    字典是一种用[键,值]形式存储元素的数据结构.也称作映射,ECMAScript6中,原生用Map实现了字典结构. 下面代码是尝试用JS的Object对象来模拟实现一个字典结构. <script& ...

  8. 获取 dhcp IP 过程分析 - 每天5分钟玩转 OpenStack(91)

    前面我们已经讨论了 DHCP agent 的配置以及 namespace 如何隔离 dnsmasq 服务,本节将以 cirros-vm1 为例分析获取 DHCP IP 的详细过程. 在创建 insta ...

  9. 好用的Markdown编辑器一览 readme.md 编辑查看

    https://github.com/pandao/editor.md https://pandao.github.io/editor.md/examples/index.html Editor.md ...

  10. Xamarin.Android-用ZXing实现二维码扫描以及连续扫描

    一.前言 本文的内容有两个基础:ZXing.Net和ZXing.Net.Mobile ZXing.Net:ZXing的C#实现,主要封装了各种二维码的编码.解码等跨平台的算法 ZXing.Net.Mo ...