先介绍CSS3动画如何使用?两步即可搞定。
-
定义动画规则
@keyframe animationName{ timeStamp{ attr1:value1; attr2:value2; ... attrn,valuen; } } 复制代码
说明:
- animationName表示动画名称;
- timeStamp表示时间点,可取值from,to或0-100%,from表示0,to表示100%;
- 每个时间点可以指定多个样式属性attr与对应值value。
-
元素应用动画
elemSelector{ animation: animationName animationDuration; } 复制代码
说明:
- 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> 复制代码
-
CSS部分
/*初始化数字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); } } 复制代码
-
JS部分
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); } 复制代码
初始化函数声明如下,
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); } 复制代码
倒计数函数声明如下,
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; } } 复制代码
这里有一个地方需要特别注意,避免以后踩坑。
关于动画样式的解绑与绑定。
动画样式animation一执行结束,就不再起作用了,要使其重新生效,需要重新绑定。我试了4种方式。
-
第一种是直接解绑,然后再绑定。
numberDiv.className = null; numberDiv.className = "number-anim"; 复制代码
结果是不能使动画重新生效。
-
第二种是使用classlist属性进行解绑定。
numberDiv.classList.toggle("number-anim"); numberDiv.classList.toggle("number-anim"); 复制代码
classList返回类名列表对象,调用toggle方法,若类名存在则删除,返回false,若类名不存在则添加,返回true,所以要调用两次,第一次删除类名,第二次添加类名。但是结果依然是不能使动画重新生效。
-
第三种是开启定时器。
先解绑,再利用定时器使浏览器重新渲染页面,重新绑定。setTimeout只是一种方式,只要能使浏览器重新渲染即可,最终动画重新生效。
numberDiv.className = null; setTimeout(function() { numberDiv.className = "number-anim"; }, 30); 复制代码
在mozilla官方文档介绍了另一种重新渲染方式,
https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Animations/Tips 复制代码
应用在这里的话,写法是,
numberDiv.className = null; window.requestAnimationFrame(function(){ window.requestAnimationFrame(function(){ numberDiv.className = "number-anim"; }); }); 复制代码
-
第四种是借助其他重新渲染途径,如颜色、内容、大小的变化。
numberDiv.className = null; numberDiv.innerHTML = num; numberDiv.style.color = getRandomColor(); numberDiv.style.fontSize = "300px"; numberDiv.className = "number-anim"; 复制代码
结果IE和Microsoft Edge 浏览器是支持的,但是FireFox和Chrome不支持, 但这是不是也说明了Chrome和FireFox已经对浏览器渲染做了优化?
简而言之,要使动画重新生效,需要触发浏览器重新渲染。
好了,附上源码链接。
https://github.com/muzhidong/frontend-demo/tree/master/countdown
复制代码