CSS3新特性详解(三):CSS3 2D转换和3D转换 transform 变形使用详解
关于CSS3新特性,在上篇博文中"CSS3新特性详解(二):CSS3 字体@font-face详解、如何创建和修改woff字体文件及text-shadow等文本效果",讨论了CSS3字体@font-face使用详解,如何创建、修改woff字体文件,以及text-shadow等css3文本效果,本文讨论CSS3的transform属性,俗称2D变换和3D变换。
transform是一个相对比较难的属性,2D转换还好点,3D转换由于涉及空间旋转、透视等比较难以理解,但是我们只要理解transform本质上就是一系列变形函数,分别是translate位移,scale缩放,rotate旋转,skew扭曲和matrix复合变换,再结合些许空间概念,那么我们一定可以驾驭transform。
1、transform定义和语法
transform 属性可使元素进行 2D 或 3D 转换,如:旋转、缩放、移动或扭曲。
语法: transform: none|transform-functions;
变形函数: translate, scale, rotate, skew, matrix, translate3d, scale3d等,具体在后续的2D转换、3D转换中会详细介绍;
2个关键特性: 普通元素经transform后,依然占DOM空间,但是又和absolute定位拥有一样的层级,DEMO如下。
.gen_box {position: relative; height: 80px;} .gen_box .box{width: 100px; height: 80px; border: 1px solid #666; margin-right: 20px; float:left;} .gen_box .box2{transform: translate(30px, 20px); background:#eee} .gen_box .box2a{position: absolute; left: 120px; top: 0; background:red} .gen_box .box2b{position: absolute; left: 120px; top: 50px; background:green; z-index:1} <div class='gen_box'> <div class="box box1">正常box1</div> <div class="box box2a">绝对定位box2a</div> <div class="box box2b">绝对定位box2b</div> <div class="box box2">位移 box2</div> <div class="box box3">正常box3</div> </div>
上图说明:
- box2 transform后,其所占的dom文档位置、空间没变,因为box3位置没发生变化;
- box2 transform后,其显示层级发生变化,比box2a高,但是比box2b低,原因是transform后box2有了absolute的层级,并且DOM节点位置在box2a后面,所以box2层级比box2a高;box2b虽然DOM位置在box2前面,由于设置了z-index其显示层级比box2高。
2、2D转换
2D转换包括:
- 一个关键属性transform-origin,变形基点设置,默认是中心点;
- 5个变形函数:translate,rotate,scale,skew,matrix;当然还有translateX、scaleX、skewX等单个维度函数;
0)transform-origin 属性
transform-origin 属性可以改变被转换元素的位置。2D 转换元素能够改变元素x和y轴。3D 转换元素还能改变Z轴。
语法: transform-origin: x-axis y-axis z-axis;
默认值: transform-origin: 50% 50% 0,中心点
参数说明:
- x-axis:基点置于X轴何处,可能的值有:left, center, right, length, %
- y-axis:基点置于y轴何处,可能的值有:top, center, bottom, length, %
- z-axis:基点置于z轴何处,可能的值有:length
关于transform-origin如何使用,参考下文rotate旋转变形函数DEMO。
1)translate, 位移
通过 translate() 方法,元素从其当前位置移动,根据给定的 left(x 坐标) 和 top(y 坐标) 位置参数:
translate(100px,20px); /* x轴平移100px,y轴平移20px,负数表示反向移动 */ translateX(10px); /* 相当于translate(10px, 0),只是x轴平移10px */ translateY(10px); /* 相当于translate(0, 10px),只是y轴平移10px */
完整DEMO,请至本文最后处下载。
2)rotate, 旋转
通过 rotate() 方法,元素顺时针旋转给定的角度。允许负值,元素将逆时针旋转:
transform: rotate(30deg); /* 顺时针旋转30度 */ transform: rotate(-30deg); /* 逆时针旋转30度 */
默认旋转基点是元素的中心点,即按照元素中心点旋转,可以通过设置transform-origin来改变旋转基点。
完整DEMO,请至本文最后处下载。
3)scale, 缩放
通过 scale变形函数,可以增加或减少元素的尺寸,根据给定的宽度(X 轴)和高度(Y 轴)参数:
transform: scale(2,4); /* 宽度为原来2倍,高度为原来4倍 */ transform: scale(2); /* 宽度,高度都为原来2倍 */ t 4000 ransform: scale(-2); /* 宽度,高度都为原来2倍,水平镜像,垂直镜像 */
除此之外还有单个维度的scaleX(n),scaleY(n).
典型应用场景: 购物站点PC端,鼠标移动宝贝图片上放大显示;
2个特性: 支持transform-origin变换基点设置,宽度和高度参数可以是负值;
- 支持transform-origin, 默认50% 50%,元素中心点;
- 宽度(X 轴)和高度(Y 轴)可以是负值,x轴负值则水平镜像,y轴负值则垂直镜像
完整DEMO,请至本文最后处下载。
几个注意事项:
- 边框,文字都会按缩放比例进行缩放;
- scaleX(2), 相当于scale(2,1),文字高度、上下边框宽度不变;
- scaleY(2), 相当于scale(1,2),文字宽度、左右边框宽度不变;
4)skew, 扭曲
语法: transform:skew(< angle > [,< angle >]);
包含两个参数值,分别表示X轴和Y轴倾斜的角度,如果第二个参数为空,则默认为0,参数为负表示向相反方向倾斜。
transform:skew(30deg, 20deg); /* x轴倾斜30度,y轴倾斜20度 */ transform:skew(30deg); /* x轴倾斜30度,y轴倾斜0度 */ transform:skewX(30deg); /* x轴倾斜30度 */ transform:skewY(20deg); /* y轴倾斜20度 */
技巧: skew坐标系不太好理解,不妨根据下则:
- x轴,垂直向下为x轴正向,然后左手握拳,拇指向下,四个手指指向为顺时针,反之逆时针;
- y轴,水平向右为y轴正向,然后左手握拳,拇指向右,四个手指指向为顺时针,反之逆时针;
根据上图坐标轴,skewX(高度不变)就很好理解啦,根据上述法则: - skewX(30deg):左手握拳,大拇指向下,四个手指向左为顺时针,所以元素沿x轴向左倾斜30度
- skewX(90deg):向左倾斜90度,则元素变成为y轴-∞处到+∞处的一条水平线,然而skewX又不能改变高度,所以将该元素定义为“消失”。
- skewX(150deg):左手握拳,大拇指向下,四个手指向左为顺时针,所以元素沿x轴向左倾斜150度,等同skewX(-30deg)
- skewY(20deg):左手握拳,大拇指向右,四个手指向下为顺时针,所以元素沿y轴向下倾斜20度;
- skew 支持transform-origin 元素基点设置;
5)matrix,矩阵
上述变形函数,scale, rotate等都可以用matrix表示,可以理解为matrix矩阵运算是scale、rotate等变形函数的实现原理,由于matrix数学专业性太强,本文不做详细阐述,具体可以参考:
3、3D转换
3D转换顾名思义就是在原2D转换基础上增加Z轴变化效果,分两部分讲解:
- transform 3D转换涉及的额外属性:transform-style,perspective,perspective-origin,backface-visibility
- transform 3D转换函数:matrix3d,translate3d等
transform 3D转换涉及的额外属性
- transform-style,让转换的子元素保留3D转换
语法: transform-style: flat|preserve-3d; 默认值flat
flat: 表示所有子元素在2D平面呈现
preserve-3d:表示所有子元素在3D空间中呈现
- perspective,规定 3D 元素的透视效果
语法: perspective: number|none; 默认值none
number: 元素距离视图的距离,以像素计。
none:同number = 0
案例DEMO,请参考:MDN perspective
- perspective-origin,设置3D元素的效果基点位置
语法: perspective-origin: x-axis y-axis;
x-axis:置于X轴何处,默认50%,可能的值有:left, center, right, length, %
y-axis:置于y轴何处,默认50%,可能的值有:top, center, bottom, length, %
案例DEMO,请参考:MDN perspective-origin
- backface-visibility,元素在不面对屏幕时是否可见
语法: backface-visibility: visible|hidden; 默认visible
案例DEMO,请参考:MDN backface-visibility
transform 3D转换 函数:
3D转换函数相对较多,列举如下,后续通过一个DEMO介绍3D函数具体使用。
- matrix3d(n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n) 定义 3D 转换,使用 16 个值的 4x4 矩阵。
- translate3d(x,y,z) 定义 3D 转化。
- translateX(x) 定义 3D 转化,仅使用用于 X 轴的值。
- translateY(y) 定义 3D 转化,仅使用用于 Y 轴的值。
- translateZ(z) 定义 3D 转化,仅使用用于 Z 轴的值。
- scale3d(x,y,z) 定义 3D 缩放转换。
- scaleX(x) 定义 3D 缩放转换,通过给定一个 X 轴的值。
- scaleY(y) 定义 3D 缩放转换,通过给定一个 Y 轴的值。
- scaleZ(z) 定义 3D 缩放转换,通过给定一个 Z 轴的值。
- rotate3d(x,y,z,angle) 定义 3D 旋转。
- rotateX(angle) 定义沿 X 轴的 3D 旋转,同rotate3d(1, 0, 0, angle)。
- rotateY(angle) 定义沿 Y 轴的 3D 旋转,同rotate3d(0, 1, 0, angle)。
- rotateZ(angle) 定义沿 Z 轴的 3D 旋转,同rotate3d(0, 0, 1, angle)。
- perspective(n) 定义 3D 转换元素的透视视图。
看个经典的六面体透视图,下图所示:
<style> .demo_box{ background:none; height:300px; border:none; } .perspective{ position:relative; width:200px; height:200px; float:left; margin:100px; transform: perspective(300px); } .perspective .face{ display:block; position:absolute; width:100%; height:100%; font-size:120px; line-height:200px; text-align:center; background:rgba(0,0,0,0.2); } .perspective .front{ transform: rotateY(0deg) translateZ(100px); background:rgba(90,90,90,.7);} .perspective .back{ transform:rotateY(180deg) translateZ(100px); background: rgba(0,210,0,.7)} .perspective .right{transform:rotateY(90deg) translateZ(100px); background:rgba(210,0,0,.7)} .perspective .left{transform:rotateY(-90deg) translateZ(100px); background: rgba(0,0,210,.7)} .perspective .top{transform:rotateX(90deg) translateZ(100px); background: rgba(210,210,0,.7)} .perspective .bottom{transform:rotateX(-90deg) translateZ(100px); background: rgba(210,0,210,.7)} </style> <div class="demo_box"> <div class="perspective"> <span class="face front">1</span> <span class="face back">2</span> <span class="face right">3</span> <span class="face left">4</span> <span class="face top">5</span> <span class="face bottom">6</span> </div> <div class="perspective" style="transform-style:preserve-3d"> <span class="face front">1</span> <span class="face back">2</span> <span class="face right">3</span> <span class="face left">4</span> <span class="face top">5</span> <span class="face bottom">6</span> </div> </div>
本文其它DEMO,代码:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>CSS3新特性-transform</title> <link rel="stylesheet" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" /> <link rel="stylesheet" href="https://cdn.bootcss.com/font-awesome/4.5.0/css/font-awesome.min.css" /> <style> .gen_box {position: relative; height: 80px;} .gen_box .box{width: 100px; height: 80px; border: 1px solid #666; margin-right: 20px; float:left;} .gen_box .box2{transform: translate(30px, 20px); background:#eee} .gen_box .box2a{position: absolute; left: 120px; top: 0; background:red} .gen_box .box2b{position: absolute; left: 120px; top: 50px; background:green; z-index:1} .table {margin-top: 80px} .table .box{position: relative; width: 101px; height: 81px; text-align: center; line-height: 80px;} .table .rect {width: 100%; height: 100%; border: 1px solid #666;} .table .ref {width: 100%; height: 100%; position: absolute; border:1px dotted #666; top:0} .table .point {width: 3px; height: 3px; border-radius: 50%; background: red; display: block; position:absolute; z-index: 9; top: 39px; left: 49px;} .table .line {display:block; font-size:0; line-height:0; position:absolute; z-index:9} .table .hline{width:116px; height:0; top: 40px; left: -8px; border-top:1px solid #666; } .table .vline{width:0px; height:96px; top: -8px; left: 50px; border-left:1px solid #666; } .table .arrow {position: absolute; display: block; width: 5px; height: 5px; } .table .arrow-t { left: 48px; top: -8px; text-indent: -999px; border-left: 1px solid #666; border-top: 1px solid #666; transform: rotate(45deg); } .table .arrow-b { left: 48px; bottom: -8px; text-indent: -999px; border-right: 1px solid #666; border-bottom: 1px solid #666; transform: rotate(45deg); } .table .arrow-r { right: -8px; top: 38px; text-indent: -999px; border-right: 1px solid #666; border-top: 1px solid #666; transform: rotate(45deg); } .table .text{position: absolute; z-index:9; font-size: 12px;} .table .text-x{left: 50px; top:25px; transform: rotate(90deg)} .table .text-y{left: 80px; top: 23px; line-height: 20px;} .skew_box .rect {background: rgba(0, 0, 255, 0.6)} .table-trans-style .box {width: 300px; height: 120px; line-height: 2;} .table .layer { background: #f69d3c; border-radius: .75rem; transform: perspective(200px) rotateY(30deg); } .layer .numeral{ background-color: #e66465; border-radius: .2rem; color: #000; margin: 1rem; padding: .2rem; transform: rotate3d(1,1,1,45deg); } </style> </head> <body style="padding-top: 20px"> <div class="container"> <div class='gen_box'> <div class="box box1">正常box1</div> <div class="box box2a">绝对定位box2a</div> <div class="box box2b">绝对定位box2b</div> <div class="box box2">位移 box2</div> <div class="box box3">正常box3</div> </div> <table class='table table-bordered translate_box'> <tr> <td> <div class="box"> <div class="rect" style="transform: translate(20px,20px)">Box1</div> <div class="ref"></div> </div> </td> <td> <div class="box"> <div class="rect" style="transform: translateX(20px)">Box2</div> <div class="ref"></div> </div> </td> <td> <div class="box"> <div class="rect" style="transform: translateY(20px)">Box3</div> <div class="ref"></div> </div> </td> <td> <div class="box"> <div class="rect" style="transform: translateX(-20px)">Box4</div> <div class="ref"></div> </div> </td> <td> <div class="box"> <div class="rect" style="transform: translateY(-20px)">Box5</div> <div class="ref"></div> </div> </td> <td> <div class="box"> <div class="rect" style="transform: translate(-20px,-20px)">Box6</div> <div class="ref"></div> </div> </td> </tr> <tr> <td>translate(20px,20px)</td> <td>translateX(20px)</td> <td>translateY(20px)</td> <td>translateX(-20px)</td> <td>translateY(-20px)</td> <td>translate(-20px,-20px)</td> </tr> </table> <table class='table table-bordered rotate_box'> <tr> <td> <div class="box box1"> <div class="rect" style="transform: rotate(30deg)">box1</div> <div class="ref"></div> <span class="point"></span> </div> </td> <td> <div class="box box2"> <div class="rect" style="transform: rotate(-30deg)">box2</div> <div class="ref"></div> <span class="point"></span> </div> </td> <td> <div class="box box3"> <div class="rect" style="transform: rotate(30deg); transform-origin: 0 0">box3</div> <div class="ref"></div> <span class="point" style="left:0; top:0;"></span> </div> </td> <td> <div class="box box4"> <div class="rect" style="transform: rotate(30deg); transform-origin: 10% 10%">box4</div> <div class="ref"></div> <span class="point" style="left:10%; top:10%;"></span> </div> </td> </tr> <tr> <td>transform: rotate(30deg)</td> <td>transform: rotate(-30deg)</td> <td>transform: rotate(30deg)<br>transform-origin: 0 0</td> <td>transform: rotate(30deg)<br>transform-origin: 10% 10%</td> </tr> </table> <table class='table table-bordered scale_box'> <tr> <td> <div class="box box1"> <div class="rect" style="transform: scale(1.3);">box1</div> <div class="ref"></div> <span class="point"></span> </div> </td> <td> <div class="box box2"> <div class="rect" style="transform: scale(1.2); transform-origin: 0 0">box2</div> <div class="ref"></div> <span class="point" style="left:0; top:0;"></span> </div> </td> <td> <div class="box box3" style="margin-right:60px"> <div class="rect" style="transform: scale(2,1.5); transform-origin: 10% 10%">box3</div> <div class="ref"></div> <span class="point" style="left:10%; top:10%;"></span> </div> </td> <td> <div class="box box4"> <div class="rect" style="transform: scaleX(1.5)">box4</div> <div class="ref"></div> <span class="point"></span> </div> </td> <td> <div class="box box5"> <div class="rect" style="transform: scaleY(-1.5)">box5</div> <div class="ref"></div> <span class="point"></span> </div> </td> <td> <div class="box box6"> <div class="rect" style="transform: scale(-1.5);">box6</div> <div class="ref"></div> <span class="point"></span> </div> </td> </tr> <tr> <td>scale(1.3)</td> <td>transform: scale(1.2); <br>transform-origin: 0 0</td> <td>transform: scale(2,1.5); <br>transform-origin: 10% 10%</td> <td>scaleX(1.5)</td> <td>scaleY(-1.5)</td> <td>scale(-1.5)</td> </tr> </table> <table class='table table-bordered skew_box'> <tr> <td> <div class="box"> <div class="rect" style="transform: skewX(30deg);"><i class='fa fa-undo'></i> box1</div> <div class="ref"></div> <span class="line vline"></span> <span class="line hline"></span> <span class="arrow arrow-b"></span> <span class="arrow arrow-r"></span> <span class="text text-x">x轴</span> <span class="text text-y">y轴</span> <span class="point"></span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skewX(90deg);">box2</div> <div class="ref"></div> <span class="line vline"></span> <span class="point"></span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skewX(150deg);">box3</div> <div class="ref"></div> <span class="line vline"></span> <span class="arrow arrow-t"></span> <span class="point"></span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skewX(180deg);">box4</div> <div class="ref"></div> <span class="line vline"></span> <span class="point"></span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skewX(210deg);">box5</div> <div class="ref"></div> <span class="line vline"></span> <span class="line hline"></span> <span class="point"></span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skewX(270deg);">box6</div> <div class="ref"></div> <span class="point"></span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skewX(300deg);">box7</div> <div class="ref"></div> <span class="point"></span> </div> </td> </tr> <tr> <td>skewX(30deg)</td> <td>skewX(90deg);</td> <td>skewX(150deg)</td> <td>skewX(180deg)</td> <td>skewX(210deg)</td> <td>skewX(270deg)</td> <td>skewX(300deg)</td> </tr> </table> <table class='table table-bordered skew_box'> <tr> <td> <div class="box"> <div class="rect" style="transform: skewX(30deg);">box1</div> <div class="ref"></div> <span class="line vline"></span> <span class="arrow arrow-b"></span> <span class="point"></span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skewX(-30deg);">box2</div> <div class="ref"></div> <span class="line vline"></span> <span class="arrow arrow-b"></span> <span class="point"></span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skewY(20deg);">box3</div> <div class="ref"></div> <span class="line hline"></span> <span class="arrow arrow-r"></span> <span class="point"></span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skewY(-20deg);">box4</div> <div class="ref"></div> <span class="line hline"></span> <span class="arrow arrow-r"></span> <span class="point"></span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skew(30deg,20deg);">box5</div> <div class="ref"></div> <span class="point"></span> <span class="line hline"></span> <span class="line vline"></span> <span class="arrow arrow-b"></span> <span class="arrow arrow-r"></span> <span class="text text-x">x轴</span> <span class="text text-y">y轴</span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skew(-30deg, -20deg);">box6</div> <div class="ref"></div> <span class="point"></span> </div> </td> <td> <div class="box"> <div class="rect" style="transform: skew(30deg,20deg); transform-origin:0 0">box7</div> <div class="ref"></div> <span class="point" style="left:0;top:0"></span> </div> </td> </tr> <tr> <td>skewX(30deg)</td> <td>skewX(-30deg);</td> <td>skewY(20deg)</td> <td>skewY(-20deg)</td> <td>skew(30deg,20deg)</td> <td>skew(-30deg, -20deg)</td> <td>skew(30deg,20deg); <br>transform-origin:0 0</td> </tr> </table> <p>案例来自 MDN</p> <table class='table table-trans-style'> <tr> <td><div class='box'> <div id="example-element" class="transition-all layer" style="transform-style: flat;"> <p>Parent</p> <div class="numeral"><code>rotate3d(1, 1, 1, 45deg)</code></div> </div></div> </td> <td><div class='box'> <div id="example-element" class="transition-all layer" style="transform-style: preserve-3d;"> <p>Parent</p> <div class="numeral"><code>rotate3d(1, 1, 1, 45deg)</code></div> </div></div> </td> </tr> <tr> <td>transform-style: flat;</td> <td>transform-style: preserve-3d;</td> </tr> </table> <div> </body> </html>
本文DEMO,所有css都没有考虑浏览器适应性,如:-moz-,-webkit-等。
关于CSS3 transform属性讲解更多资料,除了w3c教程,建议大家可以参考
- w3c css-transforms
- 简书的“CSS3 transform介绍”一文,比较幽默生动、通俗易懂。
- CSS3 Transform变形(2D转换)
- CSS3 2D转换&3D转换
- CSS3 Transform 变形(transform)、转换(transition)和动画(animation)
- CSS3中的transform变形详解
- CSS3 2D和3D转换(transform)
- 使用css3 transform 属性来变换背景图方法步骤详解
- CSS3 2D转换 3D转换
- css3 2d转换3d转换以及动画的知识点汇总
- css3属性之2D转换、3D转换、过度、动画
- CSS3实践之路(五):2D和3D转换(transform)
- Css3之高级-5 Css转换(简介、2D转换、3D转换)
- CSS3中的transform变形详解兼容ie
- css3 2d转换3d转换以及动画的知识点汇总
- css3 2d转换3d转换以及动画的知识点汇总
- [置顶] CSS3 2D转换(transform)
- transform属性——css3变形效果2D
- CSS3 2D和3D转换 Transform
- css3 2D转换(2D Transform) 动画(Animation)
- CSS3字体、2D转换、3D转换
- WPF学习05:2D绘图 使用Transform进行控件变形