3D transform (学习笔记)
原文: 张鑫旭老师的 好吧,CSS3 3D transform变换,不过如此!。
参考资料:w3school ||
CSS 3D Panorama - 淘宝造物节技术剖析
|| transform-function
|| 《css揭秘》
先来介绍以下transform 有哪些值:
- none 定义不进行转换
- martix(n,n,n,n,n,n) 定义2D转换,使用六个值的矩阵
- martix3d(n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n) 定义3D转换,使用16个值的4*4矩阵
- translate(x, y) 定义2D转换
- translate3d(x, y, z) 定义3D转换
- translateX(x) 定义转换,只用 X 轴的值
- translateY(y) 定义转换,只用 y 轴的值
- translateZ(z) 定义3D转换,只用 z 轴的值
- scale(x,y) 定义2D缩放转换
- scale3d(x, y, z) 定义3D缩放转换
- scaleX(x) 设置 x 轴的值来定义缩放转换
- scaleY(y) 设置 y 轴的值来定义缩放转换
- scaleZ(z) 设置 z 轴的值来定义缩放转换
- rotate(angle) 定义2D转换,在参数中规定角度
- rotate3d(x, y, z, angle) 定义3D转换
- rotateX(angle) 沿着 x 轴的3D旋转
- rotateY(angle) 沿着 y 轴的3D旋转
- rotateZ(angle) 沿着 z 轴的3D旋转
- skew(x-angle, y-angle) 沿着x和y轴的2D倾斜转换
- skewX(angle) 沿着 x 轴的2D倾斜转换
- skewY(angle) 沿着 y 轴的2D倾斜转换
- perspective(n) 为3D 转换元素定义透视视图
如果以电脑屏幕为参考物的话,x轴就是电脑屏幕的长, y轴就是电脑屏幕的宽,z轴就是眼睛直视电脑屏幕的距离,那么就会得到下面一张侧视图:
perspective在开始之前先解释一下几个值:
-
perspective: 指定观察者与 z = 0 平面的距离,使具有三维位置变换的元素产生透视效果。(默认值:none,值只能是绝对长度)
-
transform-style:用于指定其子元素提供2D还是3D的场景。 值: flat | preserve-3d
-
backface-visiblity: 确定当面对用户时元素背面是否可见 值: visible | hidden
-
perspective-origin: 决定观察者正在查找的位置,该位置就会消失
-
transform-box:transform-box属性定义了transform和transform-origin属性所关联的布局框。值: border-box | fill-box | view-box
-
transform-origin: 修改元素的变换原点 值: x-offset-keyword | y-offset-keyword | z-offset
我们都知道物体离的越近物体就越大,离的越远物体就越小即: 当translateZ的值小于perspective的值时,物体就越大,当translateZ的值大于perspective的值时,物体消失。
实例: 图片的旋转木马效果
原理: 让图片共用公共点,利用rotateY决定图片朝向。
关键点: 使用translateZ 远离原点
translateZ 计算:
diagram.png calc.png代码:
html
<div class="stage">
<div class="container">
![](img.jpg)
![](img1.jpg)
![](img2.jpg)
![](img.jpg)
![](img1.jpg)
![](img2.jpg)
![](img.jpg)
![](img1.jpg)
![](img2.jpg)
![](img.jpg)
</div>
</div>
css
* {
padding: 0;
margin: 0;
font-size: 14px;
}
.stage {
perspective: 800px;
width: 80%;
margin: 20% auto;
}
.container {
position: relative;
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
-ms-transform-style: preserve-3d;
-o-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-transition: -webkit-transform 1s;
-moz-transition: -moz-transform 1s;
-ms-transition: -ms-transform 1s;
-o-transition: -o-transform 1s;
transition: transform 1s;
}
img {
width: 128px;
height: 100px;
position: absolute;
left: 50%;
margin: 0 0 0 -64px;
}
.pic {
position: absolute;
bottom: 0;
border-radius: 2px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
-webkit-transition: opacity 1s, -webkit-transform 1s;
-moz-transition: opacity 1s, -moz-transform 1s;
-ms-transition: opacity 1s, -ms-transform 1s;
-o-transition: opacity 1s, -o-transform 1s;
transition: opacity 1s, transform 1s;
backface-visibility:hidden;
}
img:nth-child(1){ transform: rotateY(0deg) translateZ(195.839px); }
img:nth-child(2){ transform: rotateY(40deg) translateZ(195.839px); }
img:nth-child(3){ transform: rotateY(80deg) translateZ(195.839px); }
img:nth-child(4){ transform: rotateY(120deg) translateZ(195.839px); }
img:nth-child(5){ transform: rotateY(160deg) translateZ(195.839px); }
img:nth-child(6){ transform: rotateY(200deg) translateZ(195.839px); }
img:nth-child(7){ transform: rotateY(240deg) translateZ(195.839px); }
img:nth-child(8){ transform: rotateY(280deg) translateZ(195.839px); }
img:nth-child(9){ transform: rotateY(320deg) translateZ(195.839px); }
img:nth-child(10){ transform: rotateY(360deg) translateZ(195.839px); }
js
// CSS transform 变换应用
(function() {
var transform = function(el, val, key) {
key = key || 'Transform';
['Moz', 'Ms', 'Webkit', 'o', ''].forEach(function(prefix) {
el.style[prefix + key] = val;
});
return el;
},
// 浏览器选择器API
$ = function(selector) {
return document.querySelector(selector);
},
$$ = function(selector) {
return document.querySelectorAll(selector);
}
var imgArr = document.getElementsByClassName('pic');
var eleStage = $('.stage'), eleContent = $('.container'), indexPic = 0,
elePic = $$('pic'), transZ = 64 / Math.tan((2 / 180) * Math.PI);
var rotate = 400 / imgArr.length;
eleContent.addEventListener('click', function() {
transform(this, 'rotateY(' + (- 1 * rotate * ++indexPic) + 'deg)');
});
imgArr.forEach(function(j) {
transform($('.pic' ), 'rotateY(' + j * rotate + 'deg) translateZ(' + (transZ + 20) + 'px)');
})
})()
拓展实例:
模拟开门特效(反方向)
突然来了灵感,当然以前也看过同样的效果,当时很不解,不知道怎么实现,现在终于可以实现相类似的效果了。
使用到的属性:
- transform-style
- rotateY
- transform-origin
- animation-timing-function
- cubic-bezier
- animation
效果图:
gif.gif代码:
html
<form action="#" class="form">
<label for="username">
<i>用户名:</i><input type="text" class="username" name="username"></label>
<label for="password">
<i>密码:</i><input type="password" class="username" name="password"></label>
<button class="login-text" type="button">登录</button>
</form>
<div class="login">
<button class="login-text" type="button">登录</button>
</div>
css
* {
margin: 0;
padding: 0;
}
body {
perspective: 500px;
}
.form {
position: relative;
display: block;
width: 450px;
height: 450px;
margin: 10% auto;
background: #3B445B;
border-radius: 4px;
transform-style: preserve-3d;
transform: rotateY(0deg);
transform-origin: 0 0;
color: #f0f0f0;
animation: login-rotate 3s;
}
label {
float: left;
margin: 70px 0 0 70px;
}
.login {
position: absolute;
top: 50%;
left: 50%;
width: 400px;
height: 400px;
margin: -200px 0 0 -200px;
transform: scale(0);
background: #3B445B;
border-radius: 4px;
transform-origin: center;
animation: login-show 3s;
}
.username {
margin: 0 20px;
padding: 3px 0;
width: 200px;
font-size: 18px;
}
.login-text {
position: absolute;
bottom: 40px;
left: 70px;
width: 300px;
height: 40px;
border-radius: 4px;
background: #49D292;
border: none;
color: #f0f0f0;
font-size: 16px;
}
i {
width: 70px;
float: left;
font-style: normal;
}
@keyframes login-show {
from {
transform: scale(0);
/*opacity: 0;*/
}
10% {
opacity: 0.8;
}
80% {
transform: scale(1.1);
/*opacity: 1;*/
animation-timing-function: cubic-bezier(.1, .25, .3, 1.5);
}
90% {
/*opacity: 0;*/
}
}
@keyframes login-rotate {
from {
transform: rotateY(0deg);
opacity: 1;
}
10% {
opacity: 1;
}
80% {
transform: rotateY(90deg);
opacity: 0;
}
}
Ps: 这只是单纯的实现了特效还未与js相结合、后端数据结合。