第11章 Transform

421 阅读14分钟

一、概述

在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);
}

translate.gif

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);
}

rotate.gif

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);
}

scale.gif

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);
}

skew.gif

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-origin.gif

三、transform-3D

三维坐标系:

transform-3d-coordinate.png

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);
}

transform-style.gif

2、perspective

“perspective” 意为透视、视角,该属性定义3D元素距视图的距离(个人理解为景深),它只对转换为了3D模式的元素生效,单位为像素。

学美术或者学建筑的同学肯定接触过透视的一些东西:

perspective-1.png

perspective-2.png

不过,CSS3 3D transform中的透视的透视点与上面两张示例图是不同的:CSS3 3D transform的透视点是在浏览器的前方。或者这么理解吧:显示器中3D效果元素的透视点在显示器的上方(不是后面),近似就是我们眼睛所在方位。

比方说,一个1680像素宽的显示器中有张美女图片,应用了3D transform,同时,该元素或该元素父辈元素设置的“perspective”大小为2000像素。则这张美女呈现的3D效果就跟你本人在1.2个显示器宽度的地方(1680*1.2≈2000)看到的真实效果一致。

3d-distance.jpg

“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像素的时候,该元素看不见了——这很好理解:我们是看不见眼睛后面的东西的!

再生动的文字描述也不如一个实例来得直观,我们可以直接看示例:

perspective&translateZ.gif

代码示例(你可以忽略代码):

<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%;

transform-origin-1.png

4、backface-visibility

该属性定义当3D元素不面向屏幕时是否可见,该属性有两个值:

  • visible(默认)

    表示当3D元素通过“rotate”属性旋转到元素“背部”时,元素仍然可见。

  • hidden

    表示当3D元素通过“rotate”属性旋转到元素“背部”时,元素不可见。

  在现实世界中,我们无法穿过软妹A看到其身后的软妹B或C或D;但是,在CSS3的3D世界中,默认情况下,我们是可以看到背后的元素。因此,为了切合实际,我们常常会这样设置,使后面元素不可见:

backface-visibility:hidden;

backface-visibility-1.png

backface-visibility-2.png

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-2.png

我们来看一下演变过程,为了演示效果,我将设置 backface-visibility: visible;

transform-3D-cubic-transition.gif

演变过程源码:

<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;
}

3)、Carousel

transform-3D-carousel.gif

源码下载