# CSS3动画实现3D倒计时
先介绍CSS3动画如何使用?两步即可搞定。
# 定义动画规则
@keyframe animationName{
timeStamp{
attr1:value1;
attr2:value2;
...
attrn,valuen;
}
}
2
3
4
5
6
7
8
说明:
- animationName表示动画名称;
- timeStamp表示时间点,可取值from,to或0-100%,from表示0,to表示100%;
- 每个时间点可以指定多个样式属性attr与对应值value。
# 元素应用动画
elemSelector{
animation: animationName animationDuration;
}
2
3
说明:
- elemSelector表示元素选择器
- 执行一个动画至少指定动画名称animationName和动画时长animationDuration
- animation属性是以下属性的简写形式,每个属性的含义说明如下表,
属性名称 含义 animation-name @keyframe动画的名称 animation-duration 动画的时长,需指定单位如s或ms,默认值为0 animation-timing-function 动画的速度曲线,默认值为ease,其他取值有ease-in、ease-out、ease-in-out、linear、step-start、step-end、贝塞尔曲线函数cubic-bezier、步进函数steps animation-delay 动画延时多久开始,需指定指定单位如s或ms,默认为0,,取正值表示延时,负值表示超前 animation-iteration-count 动画播放次数,默认为1 animation-direction 动画是否在下一周期逆向播放,默认是normal,其他取值有reverse、alternate、alternate-reverse animation-play-state 动画的播放状态,是运行还是暂停,默认是running,其他取值有paused animation-fill-mode 动画执行前、后是否应用目标状态,默认是none,其他取值有forwards、backwards、both
重点来了,一个倒计时效果是如何实现的,先看效果。由于是压缩生成的gif,所以看起来会很快。
# 代码说明
HTML部分
<!--用于呈现数字--> <div id="number"></div> <!--用于重新倒计时--> <button class="button">再来一次</button> <!--用于最后的声音播放。--> <audio ></audio>
1
2
3
4
5
6CSS部分
/*初始化数字div样式*/ #number { position: absolute; top: 50%; left: 50%; text-align: center; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); } /*绑定动画*/ .number-anim { -webkit-animation: animation_in 10s linear; -moz-animation: animation_in 10s linear; /*动画时长是10s,且动画的速度是线性的*/ animation: animation_in 10s linear; } /*定义动画规则*/ @keyframes animation_in { 0 {} 10% { /*由于动画时长是10s,此时是1s时刻,字体大小变为100px,z方向距离主屏幕为300px*/ font-size: 100px; -webkit-transform: translate3d(-50%, -50%, -300px); -moz-transform: translate3d(-50%, -50%, -300px); transform: translate3d(-50%, -50%, -300px); } 11% { /*随后字体大小变为300px,z方向距离主屏幕为0,后面每到整秒数都会重复进行*/ font-size: 300px; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); } 20% { font-size: 100px; -webkit-transform: translate3d(-50%, -50%, -300px); -moz-transform: translate3d(-50%, -50%, -300px); transform: translate3d(-50%, -50%, -300px); } 21% { font-size: 300px; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); } 30% { font-size: 100px; -webkit-transform: translate3d(-50%, -50%, -300px); -moz-transform: translate3d(-50%, -50%, -300px); transform: translate3d(-50%, -50%, -300px); } 31% { font-size: 300px; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); } 40% { font-size: 100px; -webkit-transform: translate3d(-50%, -50%, -300px); -moz-transform: translate3d(-50%, -50%, -300px); transform: translate3d(-50%, -50%, -300px); } 41% { font-size: 300px; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); } 50% { font-size: 100px; -webkit-transform: translate3d(-50%, -50%, -300px); -moz-transform: translate3d(-50%, -50%, -300px); transform: translate3d(-50%, -50%, -300px); } 51% { font-size: 300px; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); } 60% { font-size: 100px; -webkit-transform: translate3d(-50%, -50%, -300px); -moz-transform: translate3d(-50%, -50%, -300px); transform: translate3d(-50%, -50%, -300px); } 61% { font-size: 300px; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); } 70% { font-size: 100px; -webkit-transform: translate3d(-50%, -50%, -300px); -moz-transform: translate3d(-50%, -50%, -300px); transform: translate3d(-50%, -50%, -300px); } 71% { font-size: 300px; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); } 80% { font-size: 100px; -webkit-transform: translate3d(-50%, -50%, -300px); -moz-transform: translate3d(-50%, -50%, -300px); transform: translate3d(-50%, -50%, -300px); } 81% { font-size: 300px; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); } 90% { font-size: 100px; -webkit-transform: translate3d(-50%, -50%, -300px); -moz-transform: translate3d(-50%, -50%, -300px); transform: translate3d(-50%, -50%, -300px); } 91% { font-size: 300px; -webkit-transform: translate3d(-50%, -50%, 0); -moz-transform: translate3d(-50%, -50%, 0); transform: translate3d(-50%, -50%, 0); } 100% { font-size: 100px; -webkit-transform: translate3d(-50%, -50%, -300px); -moz-transform: translate3d(-50%, -50%, -300px); transform: translate3d(-50%, -50%, -300px); } }
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141JS部分
window.onload = function() { //第一步:定义全局变量 num = 10;//数字内容 isCounting = true;//是否正在计数 timer = null;//定时器 numberDiv = document.querySelector("#number"); audio = document.querySelector("audio"); button = document.querySelector(".button"); //第二步:初始化 init(); //第三步:开始倒计时 timer = setInterval(count, 1000); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17初始化函数声明如下,
function init() { numberDiv.innerHTML = num; numberDiv.style.color = getRandomColor(); numberDiv.style.fontSize = "300px"; numberDiv.className = "number-anim"; button.addEventListener("click", function() { if (isCounting) { return; } isCounting = true; num = 10; numberDiv.innerHTML = num; numberDiv.style.color = getRandomColor(); numberDiv.style.fontSize = "300px"; //先解绑,再使用setTimeout使浏览器重新渲染页面,重新绑定 //setTimeout只是一种方式,只要能使浏览器重新渲染即可 numberDiv.className = null; setTimeout(function() { numberDiv.className = "number-anim"; timer = setInterval(count, 1000); }, 30); }, false); }
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倒计数函数声明如下,
function count() { numberDiv.innerHTML = --num; numberDiv.style.color = getRandomColor(); if (num == 0) { clearInterval(timer); audio.src="./audio/readygo.mp3"; audio.play(); numberDiv.innerHTML = "Ready Go!"; numberDiv.style.color = getRandomColor(); numberDiv.style.fontSize = "100px"; numberDiv.style.opacity = 0.8; numberDiv.style.filter = "alpha(opacity=80)"; CompatibleFunc(numberDiv, "Transition", "opacity 1s"); isCounting = false; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
这里有一个地方需要特别注意,避免以后踩坑。
# 关于动画样式的解绑与绑定。
动画样式animation一执行结束,就不再起作用了,要使其重新生效,需要重新绑定。我试了4种方式。
第一种是直接解绑,然后再绑定。
numberDiv.className = null; numberDiv.className = "number-anim";
1
2结果是不能使动画重新生效。
第二种是使用classlist属性进行解绑定。
numberDiv.classList.toggle("number-anim"); numberDiv.classList.toggle("number-anim");
1
2classList返回类名列表对象,调用toggle方法,若类名存在则删除,返回false,若类名不存在则添加,返回true,所以要调用两次,第一次删除类名,第二次添加类名。但是结果依然是不能使动画重新生效。
第三种是开启定时器。
先解绑,再利用定时器使浏览器重新渲染页面,重新绑定。setTimeout只是一种方式,只要能使浏览器重新渲染即可,最终动画重新生效。
numberDiv.className = null; setTimeout(function() { numberDiv.className = "number-anim"; }, 30);
1
2
3
4在mozilla官方文档介绍了另一种重新渲染方式,
https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Animations/Tips (opens new window)
应用在这里的话,写法是,
numberDiv.className = null; window.requestAnimationFrame(function(){ window.requestAnimationFrame(function(){ numberDiv.className = "number-anim"; }); });
1
2
3
4
5
6第四种是借助其他重新渲染途径,如颜色、内容、大小的变化。
numberDiv.className = null; numberDiv.innerHTML = num; numberDiv.style.color = getRandomColor(); numberDiv.style.fontSize = "300px"; numberDiv.className = "number-anim";
1
2
3
4
5
6
7结果IE和Microsoft Edge 浏览器是支持的,但是FireFox和Chrome不支持, 但这是不是也说明了Chrome和FireFox已经对浏览器渲染做了优化?
简而言之,要使动画重新生效,需要触发浏览器重新渲染。
好了,附上源码链接。
https://github.com/muzhidong/frontend-demo/tree/master/countdown (opens new window)