您的位置:首页 > Web前端 > CSS

CSS3新特性详解(三):CSS3 2D转换和3D转换 transform 变形使用详解

2019-07-07 15:27 1716 查看

  关于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教程,建议大家可以参考

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: