关键帧动画在CSS3中其实是非常常用的,我们的页面如果全都是直来直去的,就会非常生硬。在老式的页面设计中,我们通常用JQuery实现一些简单的动画,但是其效果远远不能和CSS3动画相比,而且性能也非常差。CSS3中,我们可以通过指定关键帧的方式,定义更复杂的补间动画效果(当然,浏览器毕竟不是游戏引擎,这里所指的动画主要是UI设计这个层面的)。
这里我们直接做一个比较有趣的例子,它是一个页面的「加载中」提示,可能稍显复杂,但其实并不难。
加载中外部的圆框会逐渐扩大,并逐渐透明至消失,而中间的Loading
字样则在不停的抖动,体现出页面加载不出来,自己也很着急的样子,引起使用者的共鸣。
注:这个动画录制的帧数太低,实际上非常流畅。
<div class="app">
<div class="loading"></div>
<div class="loading-txt">
<span>Loading</span>
</div>
</div>
@font-face {
font-family: "Roboto-Regular";
src: url("Roboto-Regular.ttf");
}
html {
height: 100%;
}
body {
background-image: radial-gradient(#75c9ff, #5aa4ff);
}
.loading {
/*屏幕居中*/
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
/*画一个白色的圆圈*/
width: 10rem;
height: 10rem;
border: 1rem solid #ffffff;
border-radius: 50%;
/*动画效果*/
animation: 0.7s loading-anim infinite;
}
@keyframes loading-anim {
0% {
width: 8rem;
height: 8rem;
}
100% {
width: 12rem;
height: 12rem;
opacity: 0;
}
}
.loading-txt {
/*屏幕居中*/
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width: 10rem;
height: 10rem;
/*使用Flex布局使内部文字居中*/
display:flex;
align-items:center;
justify-content:center;
/*字体颜色*/
color: #ffffff;
font-family: Roboto-Regular, sans-serif;
font-size: 1.6rem;
text-shadow: 2px 2px 10px #ffffff;
/*动画效果*/
animation: 0.1s loading-txt-anim infinite;
}
@keyframes loading-txt-anim {
0% {
transform: translateX(1px);
}
50% {
transform: translateX(-1px);
}
100% {
transform: translateX(1px);
}
}
这里我们就不用在意太多细节了,主要看@keyframes
这个写法。该标签定义了一个关键帧动画,在其他CSS定义内,通过animation
属性进行引用。
animation: 动画执行时间 | 关键帧动画名 | 播放属性,infinite表示循环,默认不循环
关键帧的定义其实非常简单,就是通过0%
,50%
等定义一个动画周期内,各个关键帧的属性,浏览器会帮我们自动补间。
上面代码中,我们动画的执行是infinite
的,如果不是循环动画,你会发现动画执行完成后,页面上的元素又恢复为了初始状态。如果想保持动画执行完成时的状态,可以添加如下CSS属性:
animation-fill-mode: forwards;
我们的代码逻辑,有时候在时序上必须依赖动画效果执行完成的回调函数。用CSS实现动画时,可以使用transitionend
和animationend
这两个事件来监听渐变动画或是关键帧动画的执行完成状态。
<button id="anim-btn">Anim</button>
<button id="reset-btn">Reset</button>
<div class="test-block"></div>
.test-block {
width: 100px;
height: 100px;
background-color: #ff0000;
}
.test-block-anim {
animation: 1s transform-animation;
animation-fill-mode: forwards;
}
@keyframes transform-animation {
0% {
transform: translateX(0);
}
100% {
transform: translateX(100px);
}
}
window.onload = function () {
var btn = document.querySelector('#anim-btn');
var reset = document.querySelector('#reset-btn');
var block = document.querySelector('.test-block');
btn.onclick = function () {
block.classList.add('test-block-anim');
};
reset.onclick = function () {
block.classList.remove('test-block-anim');
};
var callback = function () {
console.log('动画执行完成了');
};
block.addEventListener('animationend', callback);
};
注意:这里千万不要用setTimeout()
等方式来实现,用延时来保证回调时序是非常不靠谱的做法。