一、概述
在CSS中执行变形转换的属性是CSS3属性中的 transform,能够执行“位移”、“旋转”、“缩放”、“倾斜”、“翻转”和“透视”等变形转换的设置,可以让Web页面的表现更加的“活跃”,增加页面的交互感,给用户留下更深的“印象”。但在用该属性进行设置时,特别是用于生产环境中时,一定要控制一个“度”,也就是说要避免“过度设计”,否则反而会让“印象”这一词有了贬义的意思。
二、transform
1、translate *
该属性值可以让元素从当前位置根据“ left(X轴)”参数和“ top(Y轴)”参数的设置在水平和垂直方向进行移动。它和用于布局的“ position ”属性,特别是当它的“ position ”的值为“ relative ”时十分相似,在进行移动后,自身的位置仍然保留,也不会影响到其它元素的位置,但有存在着区别:
- “translate”可以作用于已经执行了“绝对定位(position:absolute)”的元素,而要用“position”已经设置为了“绝对定位”的元素使用“相对定位(position:relative)”需要对布局进行重新计算,或修改DOM的标签嵌套方式。
- 使用“translate”可以让 GPU 参与运算,动画的 FPS 更高。
- 使用“translate”可以让动画的像素精确到浮点数,而使用“position”属性的值最小执行动画的单位是1像素。
所以说,“position”属性是为布局而生,而“Transform”的“translate”是为动画而生。
该属性值有一下几种类型:
translateX( x ):设置元素在X轴方向的偏移translateY( y ):设置元素在Y轴方向的偏移translateZ( z):设置元素在Z轴方向的偏移translate( x, y ):同时设置元素在X轴和Y轴方向的偏移
<div class="wrap">
<section class="box red-box">translateX</section>
<section class="box green-box">translateY</section>
<section class="box blue-box">translate</section>
</div>
.wrap {
text-align: center;
}
.wrap > .box {
width: 150px;
height: 150px;
margin: 75px;
display: inline-block;
cursor: pointer;
text-align: center;
line-height: 150px;
letter-spacing: 2px;
font-size: 20px;
color: #fff;
-webkit-transition: all .25s linear;
-moz-transition: all .25s linear;
-ms-transition: all .25s linear;
-o-transition: all .25s linear;
transition: all .25s linear;
}
.wrap > .red-box {
background-color: red;
}
.wrap > .red-box:hover {
-webkit-transform: translateX(150px);
-moz-transform: translateX(150px);
-ms-transform: translateX(150px);
-o-transform: translateX(150px);
transform: translateX(150px);
}
.wrap > .green-box {
background-color: green;
}
.wrap > .green-box:hover {
-webkit-transform: translateY(150px);
-moz-transform: translateY(150px);
-ms-transform: translateY(150px);
-o-transform: translateY(150px);
transform: translateY(150px);
}
.wrap > .blue-box {
background-color: blue;
}
.wrap > .blue-box:hover {
-webkit-transform: translate(-150px, 150px);
-moz-transform: translate(-150px, 150px);
-ms-transform: translate(-150px, 150px);
-o-transform: translate(-150px, 150px);
transform: translate(-150px, 150px);
}
2、rotate *
该属性值会让元素以当前元素的中心(X=width/2,Y=height/2)进行旋转(若不对“transform-origin”进行设置),旋转的角度为参数所设定的值,“正数”是顺时针,“负数”是逆时针,单位为“deg”。
该属性有三种类型:
rotateX( angle ):设置元素在X轴方向的旋转rotateY( angle ):设置元素在Y轴方向的旋转rotateZ( angle ):设置元素在Z轴方向的旋转
<div class="wrap">
<section class="box red-box">rotateX</section>
<section class="box green-box">rotateY</section>
<section class="box blue-box">rotateZ</section>
</div>
.wrap {
text-align: center;
}
.wrap > .box {
width: 150px;
height: 150px;
margin: 75px;
display: inline-block;
cursor: pointer;
text-align: center;
line-height: 150px;
letter-spacing: 2px;
font-size: 20px;
color: #fff;
-webkit-transition: all 1s linear;
-moz-transition: all 1s linear;
-ms-transition: all 1s linear;
-o-transition: all 1s linear;
transition: all 1s linear;
}
.wrap > .red-box {
background-color: red;
}
.wrap > .red-box:hover {
-webkit-transform: rotateX(360deg);
-moz-transform: rotateX(360deg);
-ms-transform: rotateX(360deg);
-o-transform: rotateX(360deg);
transform: rotateX(360deg);
}
.wrap > .green-box {
background-color: green;
}
.wrap > .green-box:hover {
-webkit-transform: rotateY(360deg);
-moz-transform: rotateY(360deg);
-ms-transform: rotateY(360deg);
-o-transform: rotateY(360deg);
transform: rotateY(360deg);
}
.wrap > .blue-box {
background-color: blue;
}
.wrap > .blue-box:hover {
-webkit-transform: rotateZ(360deg);
-moz-transform: rotateZ(360deg);
-ms-transform: rotateZ(360deg);
-o-transform: rotateZ(360deg);
transform: rotateZ(360deg);
}
3、scale *
该属性值会让元素以当前元素的中心进行缩放,参数的值为一个整数或浮点数,如:“1(默认)”不进行缩放,“0.8”缩小为原来的80%,“1.5”扩大到原来的150%,参数不需要单位。
该属性值有三种类型:
sclaeX ( x ):设置元素在X轴方向的缩放sclaeY ( y ):设置元素在Y轴方向的缩放sclae ( x, y ):设置元素在X轴及Y轴方向的缩放
<div class="wrap">
<section class="box red-box">scaleX</section>
<section class="box green-box">scaleY</section>
<section class="box blue-box">scale</section>
</div>
.wrap {
text-align: center;
}
.wrap > .box {
width: 150px;
height: 150px;
margin: 75px;
display: inline-block;
cursor: pointer;
text-align: center;
line-height: 150px;
letter-spacing: 2px;
font-size: 20px;
color: #fff;
-webkit-transition: all .25s linear;
-moz-transition: all .25s linear;
-ms-transition: all .25s linear;
-o-transition: all .25s linear;
transition: all .25s linear;
}
.wrap > .red-box {
background-color: red;
}
.wrap > .red-box:hover {
-webkit-transform: scaleX(.8);
-moz-transform: scaleX(.8);
-ms-transform: scaleX(.8);
-o-transform: scaleX(.8);
transform: scaleX(.8);
}
.wrap > .green-box {
background-color: green;
}
.wrap > .green-box:hover {
-webkit-transform: scaleY(2);
-moz-transform: scaleY(2);
-ms-transform: scaleY(2);
-o-transform: scaleY(2);
transform: scaleY(2);
}
.wrap > .blue-box {
background-color: blue;
}
.wrap > .blue-box:hover {
-webkit-transform: scale(1.1, 1.3);
-moz-transform: scale(1.1, 1.3);
-ms-transform: scale(1.1, 1.3);
-o-transform: scale(1.1, 1.3);
transform: scale(1.1, 1.3);
}
4、skew
该属性值会让元素根据水平(X轴)和垂直(Y轴)线参数设定倾斜角度。这里的X轴和Y轴与我们平时认为的坐标系的XY轴正好相反;且X轴正值是逆时针变形,而**Y轴正值是顺时针变形。**基点默认为中心点。
该属性值有三种类型:
skewX( angle ):设置元素在水平轴方向的倾斜skewY( angle ):设置元素在垂直轴方向的倾斜skew( x-angle, y-angle ):设置元素在水平轴及垂直轴方向的倾斜
<div class="wrap">
<section class="box red-box">skewX</section>
<section class="box green-box">skewY</section>
<section class="box blue-box">skew</section>
</div>
.wrap {
text-align: center;
}
.wrap > .box {
width: 150px;
height: 150px;
margin: 75px;
display: inline-block;
cursor: pointer;
text-align: center;
line-height: 150px;
letter-spacing: 2px;
font-size: 20px;
color: #fff;
-webkit-transition: all .25s linear;
-moz-transition: all .25s linear;
-ms-transition: all .25s linear;
-o-transition: all .25s linear;
transition: all .25s linear;
}
.wrap > .red-box {
background-color: red;
}
.wrap > .red-box:hover {
-webkit-transform: skewX(45deg);
-moz-transform: skewX(45deg);
-ms-transform: skewX(45deg);
-o-transform: skewX(45deg);
transform: skewX(45deg);
}
.wrap > .green-box {
background-color: green;
}
.wrap > .green-box:hover {
-webkit-transform: skewY(45deg);
-moz-transform: skewY(45deg);
-ms-transform: skewY(45deg);
-o-transform: skewY(45deg);
transform: skewY(45deg);
}
.wrap > .blue-box {
background-color: blue;
}
.wrap > .blue-box:hover {
-webkit-transform: skew(15deg, 20deg);
-moz-transform: skew(15deg, 20deg);
-ms-transform: skew(15deg, 20deg);
-o-transform: skew(15deg, 20deg);
transform: skew(15deg, 20deg);
}
5、transform 组合值 *
和其它具有分支属性的CSS属性一样,transform 属性也能采用多值组合的方式来实现一个CSS的复杂效果,有一点需要特别注意的是,若该属性配合过渡CSS特效 transition 属性来使用的话,值的先后顺序不一样,很多时候效果也是不一样的,需要根据需要去调整值设置的顺序。
.wrap {
transform: scale(1.5) translateX(500px);
}
6、transform-origin *
该属性用于设置旋转元素的原点(基点)位置,默认为元素的中点。可以为3种类型的值:“方位英文单词”,“Web常用长度单位”,“百分数”。
-
方位英文单词
有“top”、“right”、“bottom”、“left”和“center”5个值可以使用,如“top left”表示左上角,“right bottom”表示右下角,“center center”表示默认的中点。
-
Web常用长度单位
如最常用的像素“px”,字符“em”,点“pt”等,如:“16px 20px”表示旋转的轴在“X轴”的16像素,“Y轴(向下为正,向上为负)”的20像素的位置。
-
百分数
第一个百分数表示相对于元素宽度的百分比位置,第二个百分数表示相对于元素高度的百分比位置,如:“0% 0%”相当于左上角,“50% 50%”相当于默认的中点,“100% 100%”相当于元素的右下角。
<div class="wrap">
<section>1</section>
<section>2</section>
<section>3</section>
<section>4</section>
<section>5</section>
</div>
.wrap {
border: 1px solid #808080;
border-radius: 5px;
margin: 250px 190px;
display: flex;
justify-content: space-around;
align-items: center;
}
.wrap section {
width: 160px;
height: 160px;
background-color: red;
margin: 30px auto;
cursor: pointer;
text-align: center;
line-height: 160px;
font-size: 30px;
color: #fff;
-webkit-transition: transform 1s linear;
-moz-transition: transform 1s linear;
-ms-transition: transform 1s linear;
-o-transition: transform 1s linear;
transition: transform 1s linear;
}
.wrap section:nth-child(odd) {
background-color: blue;
}
/*设置原点*/
.wrap section:first-child {
-webkit-transform-origin: top left;
transform-origin: top left;
}
.wrap section:nth-child(2) {
-webkit-transform-origin: top right;
transform-origin: top right;
}
.wrap section:nth-child(3) {
-webkit-transform-origin: 50% 50%;
transform-origin: 50% 50%;
}
.wrap section:nth-child(4) {
-webkit-transform-origin: bottom left;
transform-origin: bottom left;
}
.wrap section:last-child {
-webkit-transform-origin: bottom right;
transform-origin: bottom right;
}
/*设置动画*/
.wrap section:active {
-webkit-transform: rotateZ(360deg);
-moz-transform: rotateZ(360deg);
-ms-transform: rotateZ(360deg);
-o-transform: rotateZ(360deg);
transform: rotateZ(360deg);
}
三、transform-3D
三维坐标系:
1、transform-style
该属性规定如何在3D空间中呈现被嵌套的元素(是子元素,而不是元素本身),它主要有两个值:
- flat:(默认)表示所有子元素在2D平面呈现。
- preserve-3d:表示所有子元素在3D空间中呈现。
当“transform-style”的值为“preserve-3D”时更贴近我们现实中的思维,因为平时我们眼睛所看到的东西都是“3D(立体)”的,而当值为“flat”的时候,就相当于在纸上画画,无论画功再好,画出的东西都是平面的,只是由于透视和明暗关系,有的时候看起来“很立体”罢了。
<div class="wrap">
<section class="t1">
<span>Flat</span>
</section>
<section class="t2">
<span>Preserve-3d</span>
</section>
</div>
.wrap {
text-align: center;
}
.wrap section {
width: 160px;
height: 160px;
background-color: #000;
margin: 30px;
display: inline-block;
}
.wrap section > span {
width: inherit;
height: inherit;
cursor: pointer;
background-color: orange;
opacity: .75;
color: #fff;
font-size: 20px;
letter-spacing: 2px;
display: flex;
justify-content: center;
align-items: center;
-webkit-transition: all .75s linear;
-moz-transition: all .75s linear;
-ms-transition: all .75s linear;
-o-transition: all .75s linear;
transition: all .75s linear;
}
.wrap > section.t1 {
/*2d场景*/
transform-style: flat;
}
.wrap > section.t2 {
/*3d场景*/
transform-style: preserve-3d;
}
.wrap section > span:hover {
-webkit-transform: rotateX(35deg) rotateY(45deg);
-moz-transform: rotateX(35deg) rotateY(45deg);
-ms-transform: rotateX(35deg) rotateY(45deg);
-o-transform: rotateX(35deg) rotateY(45deg);
transform: rotateX(35deg) rotateY(45deg);
}
2、perspective
“perspective” 意为透视、视角,该属性定义3D元素距视图的距离(个人理解为景深),它只对转换为了3D模式的元素生效,单位为像素。
学美术或者学建筑的同学肯定接触过透视的一些东西:
不过,CSS3 3D transform中的透视的透视点与上面两张示例图是不同的:CSS3 3D transform的透视点是在浏览器的前方。或者这么理解吧:显示器中3D效果元素的透视点在显示器的上方(不是后面),近似就是我们眼睛所在方位。
比方说,一个1680像素宽的显示器中有张美女图片,应用了3D transform,同时,该元素或该元素父辈元素设置的“perspective”大小为2000像素。则这张美女呈现的3D效果就跟你本人在1.2个显示器宽度的地方(1680*1.2≈2000)看到的真实效果一致。
“perspective”属性有两种使用方式,一种是直接作为一个属性去使用,即“perspective:400”的形式;还有一种形式是作为“Transform”属性的值去使用,这个时候就需要加上单位了,即:“transform: perspective(400px)”。为了浏览器兼容,我们需加上浏览器前缀。
.stage {
perspective: 600px;
}
.stage .box {
transform: perspective(600px) rotateY(45deg);
}
我们可以通过 “translateZ” 寻找透视位置,如果说 rotateX / rotateY / rotateZ可以帮助理解三维坐标,则 translateZ则可以帮你理解透视位置。
我们都知道近大远小的道理,对于没有 rotateX 以及 rotateY 的元素,translateZ 的功能就是让元素在自己的眼前或近或远。比方说,我们设置元素 perspective 为201像素,如下:
perspective: 201px;
则其子元素,设置的 translateZ值越小,则子元素大小越小(因为元素远去,我们眼睛看到的就会变小);translateZ值越大,该元素也会越来越大,当translateZ值非常接近201像素,但是不超过201像素的时候(如200像素),该元素的大小就会撑满整个屏幕(如果父辈元素没有类似 overflow:hidden 的限制的话)。因为这个时候,子元素正好移到了你的眼睛前面,所谓“一叶蔽目,不见泰山”,就是这么回事。当 translateZ 值再变大,超过201像素的时候,该元素看不见了——这很好理解:我们是看不见眼睛后面的东西的!
再生动的文字描述也不如一个实例来得直观,我们可以直接看示例:
代码示例(你可以忽略代码):
<form action="">
<label>0</label>
<input type="range" min="0" max="202" value="0" id="oRange">
<label>202</label>
</form>
<div class="stage">
<section class="box" id="box">translateZ:0</section>
</div>
form {
text-align: center;
}
.stage {
transform-style: preserve-3d;
perspective: 201px;
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}
.stage .box {
width: 120px;
height: 50px;
background-color: red;
display: flex;
justify-content: center;
align-items: center;
}
var oRange = document.getElementById('oRange');
var oBox = document.getElementById('box');
var oShowArea = document.getElementById('show-area');
oRange.oninput = function () {
oBox.textContent = 'translateZ:' + this.value;
oBox.style.cssText = 'transform: translateZ(' + this.value + 'px);';
}
3、perspective-origin
perspective-origin 表示眼睛所看的位置。默认就是所看舞台或元素的中心。有时候,我们对中心的位置是不感兴趣的,希望视线放在其他一些地方,就可以通过这个属性进行调整。
下面为立方体的实际应用 / 透视效果图:
perspective-origin: 20% 30%;
4、backface-visibility
该属性定义当3D元素不面向屏幕时是否可见,该属性有两个值:
-
visible(默认)
表示当3D元素通过“rotate”属性旋转到元素“背部”时,元素仍然可见。
-
hidden
表示当3D元素通过“rotate”属性旋转到元素“背部”时,元素不可见。
在现实世界中,我们无法穿过软妹A看到其身后的软妹B或C或D;但是,在CSS3的3D世界中,默认情况下,我们是可以看到背后的元素。因此,为了切合实际,我们常常会这样设置,使后面元素不可见:
backface-visibility:hidden;
5、Transform-3d effect
1)、Cubic Box
<div class="cubic-box">
<section class="face front">FRONT</section>
<section class="face back">BACK</section>
<section class="face left">LEFT</section>
<section class="face right">RIGHT</section>
<section class="face top">TOP</section>
<section class="face bottom">BOTTOM</section>
</div>
.cubic-box {
width: 160px;
height: 160px;
transform-style: preserve-3d;
transform: rotateX(30deg) rotateY(30deg);
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
}
.cubic-box .face {
width: inherit;
height: inherit;
/*设置背面不可见*/
backface-visibility: hidden;
opacity: .75;
/*设置文本样式*/
color: #fff;
font-size: 30px;
letter-spacing: 2px;
display: flex;
justify-content: center;
align-items: center;
/*绝对定位,让所有的子元素全部重叠在一起*/
position: absolute;
}
/*设置每一个面的背景颜色*/
.front { background-color: red; }
.back { background-color: green; }
.left { background-color: blue; }
.right { background-color: orange;}
.top { background-color: purple;}
.bottom { background-color: black; }
/*布局每一个面*/
.front { transform: translateZ(80px);}
.back { transform: rotateY(180deg) translateZ(80px);}
.left { transform: rotateY(90deg) translateZ(80px);}
.right { transform: rotateY(-90deg) translateZ(80px);}
.top { transform: rotateX(90deg) translateZ(80px);}
.bottom{ transform: rotateX(-90deg) translateZ(80px);}
我们来看一下演变过程,为了演示效果,我将设置 backface-visibility: visible;。
演变过程源码:
<div class="btn"></div>
<div class="cubic-box">
<section class="face front">FRONT</section>
<section class="face back">BACK</section>
<section class="face left">LEFT</section>
<section class="face right">RIGHT</section>
<section class="face top">TOP</section>
<section class="face bottom">BOTTOM</section>
</div>
.btn {
width: 70px;
height: 70px;
border-radius: 50%;
background-color: #000;
text-align: center;
line-height: 70px;
cursor: pointer;
margin: 110px auto;
color: #fff;
font-size: 16px;
letter-spacing: 2px;
}
.cubic-box {
width: 160px;
height: 160px;
transform-style: preserve-3d;
transform: rotateX(30deg) rotateY(30deg);
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
}
.cubic-box .face {
width: inherit;
height: inherit;
/*设置背面不可见*/
/*backface-visibility: hidden;*/
opacity: .75;
/*设置文本样式*/
color: #fff;
font-size: 30px;
letter-spacing: 2px;
display: flex;
justify-content: center;
align-items: center;
/*绝对定位,让所有的子元素全部重叠在一起*/
position: absolute;
}
/*设置每一个面的背景颜色*/
.front { background-color: red; transition: all 1s linear;}
.back { background-color: green; transition: all 1s linear 1s;}
.left { background-color: blue; transition: all 1s linear 2s;}
.right { background-color: orange;transition: all 1s linear 3s;}
.top { background-color: purple;transition: all 1s linear 4s;}
.bottom { background-color: black; transition: all 1s linear 5s;}
/*布局每一个面*/
.btn:active + .cubic-box .front { transform: translateZ(80px);}
.btn:active + .cubic-box .back { transform: rotateY(180deg) translateZ(80px);}
.btn:active + .cubic-box .left { transform: rotateY(90deg) translateZ(80px);}
.btn:active + .cubic-box .right { transform: rotateY(-90deg) translateZ(80px);}
.btn:active + .cubic-box .top { transform: rotateX(90deg) translateZ(80px);}
.btn:active + .cubic-box .bottom{ transform: rotateX(-90deg) translateZ(80px);}
/*动效设计*/
@keyframes shine {
0% { box-shadow: 0px 0px 5px 1px skyblue;}
50% { box-shadow: 0px 0px 10px 7px lightgrey;}
100%{ box-shadow: 0px 0px 5px 1px skyblue;}
}
.btn { transition: all 1s linear; }
.btn:active {
transform: scale(.75, .75);
animation: shine .5s linear infinite alternate;
}