一、前言

之前写过 《CSS3 动画简单入门》 ,文章内容只是简单介绍 CSS3 动画属性的使用,并没有一个综合的案例演示,因此本章作为前者的内容补充。

下面简单介绍本章需要实现的 3D 效果:

当加载页面后,图片展示“摊牌”的效果,当鼠标点击页面左滑动或者右滑动时,图片会跟随左旋转或右旋转。当鼠标点击页面上滑动或下滑动时,可以改变观察图片的角度。

二、实现

2.1 布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html onselectstart="return false">

<head>
<meta charset="utf-8">
<title>3D相册</title>
<link href="css/style.css" rel="stylesheet">
</head>

<body>
<div class="container">
<div id="wrap" class="images">
<img src="images/01.png" alt="">
<img src="images/02.png" alt="">
<img src="images/03.png" alt="">
<img src="images/04.png" alt="">
<img src="images/05.png" alt="">
<img src="images/06.png" alt="">
<img src="images/07.png" alt="">
<img src="images/08.png" alt="">
<img src="images/09.png" alt="">
<img src="images/10.png" alt="">
<img src="images/11.png" alt="">
</div>
</div>
<script src="script/main.js"></script>
</body>

</html>

没有样式的效果图:

2.2 样式

style.css 文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
* {
margin: 0px;
padding: 0px;
}

body {
background-color: #000;
}

.container {
perspective: 1500px;
}

.images {
width: 100px;
height: 100px;
margin: 150px auto;
position: relative;
transform: rotateX(-20deg);
transform-style: preserve-3d;/*切换 3D 效果*/
}

.images img {
position: absolute;
box-shadow: 0 0 8px #eee;
}

添加样式的效果图:

图片被设置 position: absolute; 后,所有图片重叠在一起了。

2.3 事件

从演示图中我们可以看出,3D 效果可以分 2 个步骤:摊牌效果和图片旋转效果。

2.3.1 摊牌效果

所有图片分摊 360 度,设置其旋转角度即可。

main.js 文件内容:

1
2
3
4
5
6
7
8
9
10
11
window.onload = function() {
var wrap = document.getElementById("wrap");
var images = document.getElementsByTagName("img");
var length = images.length;
var deg = 360 / length;

for (var i = 0; i < length; i++) {
images[i].style.transform = "rotateY(" + deg * i + "deg) translateZ(240px)";
images[length - i - 1].style.transition = "1s " + 0.2 * i + "s";
}
}

演示效果和动态图一样,此处省略。

所有图片包含在 div 中,当图片设置 rotateY 时,图片会以该 div 作为中心轴旋转。

图片还设置了 transition 属性,第一个参数表示过渡时间,第二个参数表示延迟时间。

2.3.2 旋转效果

实现图片旋转效果,只要改变中心轴的旋转角度即可。

main.js 文件完整内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
window.onload = function() {
var wrap = document.getElementById("wrap");
var images = document.getElementsByTagName("img");
var length = images.length;
var deg = 360 / length;

for (var i = 0; i < length; i++) {
images[i].style.transform = "rotateY(" + deg * i + "deg) translateZ(240px)";
images[length - i - 1].style.transition = "1s " + 0.2 * i + "s";
}

// 点击坐标
var clickX, clickY;
// 移动坐标
var moveX, moveY;
// 移动距离坐标
var minusX, minusY;
// 旋转角度
var rotateX = 0,
rotateY = -20;
var timer = null;
// 鼠标按下事件
document.onmousedown = function(e) {
clickX = e.clientX;
clickY = e.clientY;
// 鼠标移动
this.onmousemove = function(e) {
moveX = e.clientX;
moveY = e.clientY;
// 移动距离
minusX = moveX - clickX;
minusY = moveY - clickY;
// 旋转角度,避免旋转太快故* 0.1
rotateX += minusX * 0.1;
rotateY -= minusY * 0.1;
// 中心轴旋转
wrap.style.transform = "rotateX(" + rotateY + "deg) rotateY(" + rotateX + "deg)"

clickX = moveX;
clickY = moveY;
}

// 鼠标释放
this.onmouseup = function() {
this.onmousemove = null;

// 旋转惯性
timer = setInterval(function() {
minusX *= 0.99;
minusY *= 0.98;
// 旋转角度
rotateX += minusX * 0.2;
rotateY -= minusY * 0.1;
// 中心轴旋转
wrap.style.transform = 'rotateX(' + rotateY + 'deg) rotateY(' + rotateX + 'deg) ';

if (Math.abs(minusX) < 0.1 && Math.abs(minusY) < 0.1) {
clearInterval(timer);
}
}, 10);
}
}
}

三、源码

rotate-photo-album