CSS3 使运动变得更加简单了,我们只需用少量的代码,就可以写出数行甚至更多 JavaScript 代码的效果,并且 CSS3 处理诸如旋转、倾斜、3D 等效果的能力是远强于 JavaScript 的。你能用 JavaScript 让一个 div 渲染任意角度吗?也许能,但复杂度肯定超乎想象,而这个效果可以使用 CSS3 一个函数轻松搞定。
有了 CSS3 写动画,就可以完全抛弃 JavaScript 了吗?当然不是。CSS3 强在表现,JavaScript 强在逻辑,二者结合可以发挥最大的威力。
CSS3 中实现动画效果可能会用到这几个属性:
- transition
- transform
- animation
这几个属性构成了 CSS3 丰富多彩的动画世界。
transition
这是 CSS3 的一个属性,意为过渡。该属性用在某个元素上,用来定义该元素的属性发生变化时,呈现出的过渡效果。
transition 有几个属性值:
- transition-property:需要应用过渡效果的属性名称
- transition-duration:完成该过渡效果所需的时间
- transition-timing-function:过渡效果
- transition-delay:延迟时间(默认为 0)
transition-timing-function 有下列可选值:
- linear:匀速过渡
- ease:先慢后快再慢过渡
- ease-in:先慢后快过渡
- ease-out:先快后慢过渡
- ease-in-out:先慢后快再慢过渡
- cubic-bezier:根据贝赛尔曲线过渡
这系列规则可以合写为:
transiton:<transition-property> <transition-duration> <transition-timing-function> <transition-delay>
如果想根据属性定义不同的过渡,可以这样写(以宽高为例):
transition:width 1s ease-in,height 0.5s ease-out 1s;
贝赛尔曲线用来定义更加复杂的过渡,如果我们想要一个自定义的过渡效果,就可以使用贝塞尔曲线,这个网站可以将贝塞尔曲线转换为相应的 CSS3 函数,推荐使用。
关于这些属性的记忆,这里给出了一个羞羞的方式。
transitionend 事件
transitionend 事件是在过渡效果完成后触发
ele.addEventListener("transitionend",fun);
注:元素的每个属性过渡完成后都会触发一次 transitionend 事件。
transform
transform 用来对元素进行 2D/3D 上的属性转换。简单说来,使用该属性,可以对物体上进行形状上的变化,如倾斜,旋转。可以让物体在 2D 或者 3D 空间下展示,让物体在空间中进行位移等。常用的有这么些属性:
- scale:对元素进行缩放
- rotate:对元素进行旋转
- skew:对元素进行倾斜变换
- translate:对元素进行位移
- scale3d:3D 场景下缩放
- rotate3d:3D 场景下旋转
- skew3d:3D 场景下倾斜
- translate3d:3D 场景下位移
详细的用法可以参考这里。
下面是一个动态时钟的例子。
动态时钟
先来看下布局:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>取个什么名字好呢</title>
<style>
/* 外层容器 */
#box{
width: 460px;
height: 460px;
margin: 100px auto;
position: relative;
border-radius: 50%;
}
/* 指针容器 */
.pointers{
width: 20px;
height: 20px;
position: absolute;
left: calc(50% - 10px);
top: calc(50% - 10px);
background: #000;
border-radius: 50%;
}
/* 时针 */
#hour{
width: 10px;
height: 70px;
background: #000;
position: absolute;
left: calc(50% - 5px);
top: -60px;
transform-origin: center 70px;
transform: rotate(-45deg);
z-index: -1;
}
/* 分针 */
#min{
width: 6px;
height: 100px;
background: #ccc;
position: absolute;
left: calc(50% - 3px);
top: -90px;
transform: rotate(45deg);
transform-origin: center 100px;
z-index: -1;
}
/* 秒针 */
#sec{
width: 4px;
height: 140px;
background: red;
position: absolute;
left: calc(50% - 2px);
top: -130px;
transform: rotate(90deg);
transform-origin: center 140px;
z-index: -1;
}
#dial{
width: 460px;
height: 460px;
background: rgba(0,0,0,0.2);
margin: 0;
padding: 0;
list-style: none;
position: relative;
display: flex;
justify-content: center;
}
#dial li{
width: 4px;
height: 10px;
background: #000;
position: absolute;
transform-origin: center 230px;
}
#dial li{
width: 4px;
height: 10px;
background: #000;
position: absolute;
transform-origin: center 230px;
}
#dial li:nth-of-type(1){
height: 20px;
width: 10px;
}
#dial li:nth-of-type(2){
transform: rotate(6deg);
}
#dial li:nth-of-type(3){
transform: rotate(12deg);
}
#dial li:nth-of-type(4){
transform: rotate(18deg);
}
#dial li:nth-of-type(5){
transform: rotate(24deg);
}
</style>
</head>
<body>
<div id="box">
<!-- 刻度 -->
<ul id="dial">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<!-- 指针 -->
<div class = "pointers">
<div id = "hour"></div>
<div id="min"></div>
<div id="sec"></div>
</div>
</div>
</body>
</html>
transform-orgin 属性指定元素 transform 时的基准点,默认为元素的中心(center center),我们可以将 transform-origin 指定为页面上的任意一个点。
布局效果如图:
接下来画出剩余的其他刻度:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>取个什么名字好呢</title>
<style>
/* 外层容器 */
#box{
width: 460px;
height: 460px;
margin: 100px auto;
position: relative;
border-radius: 50%;
}
/* 指针容器 */
.pointers{
width: 20px;
height: 20px;
position: absolute;
left: calc(50% - 10px);
top: calc(50% - 10px);
background: #000;
border-radius: 50%;
}
/* 时针 */
#hour{
width: 10px;
height: 70px;
background: #000;
position: absolute;
left: calc(50% - 5px);
top: -60px;
transform-origin: center 70px;
transform: rotate(-45deg);
z-index: -1;
}
/* 分针 */
#min{
width: 6px;
height: 100px;
background: #ccc;
position: absolute;
left: calc(50% - 3px);
top: -90px;
transform: rotate(45deg);
transform-origin: center 100px;
z-index: -1;
}
/* 秒针 */
#sec{
width: 4px;
height: 140px;
background: red;
position: absolute;
left: calc(50% - 2px);
top: -130px;
transform: rotate(90deg);
transform-origin: center 140px;
z-index: -1;
}
#dial{
width: 460px;
height: 460px;
background: rgba(0,0,0,0.2);
margin: 0;
padding: 0;
list-style: none;
position: relative;
display: flex;
justify-content: center;
}
#dial li{
width: 4px;
height: 10px;
background: #000;
position: absolute;
transform-origin: center 230px;
}
#dial li{
width: 4px;
height: 10px;
background: #000;
position: absolute;
transform-origin: center 230px;
}
</style>
</head>
<body>
<div id="box">
<!-- 刻度 -->
<ul id="dial"></ul>
<!-- 指针 -->
<div class = "pointers">
<div id = "hour"></div>
<div id="min"></div>
<div id="sec"></div>
</div>
</div>
</body>
<script>
(function (){
const dial = document.getElementById("dial");
let dials = "";
for(let i = 0; i < 60; i++){
let tmp = "";
if(i % 5 === 0){
tmp = `<li style = " width:10px;height:20px;transform:rotate(${6 * i}deg)"></li>`;
}else{
tmp = `<li style = "transform:rotate(${6 * i}deg)"></li>`;
}
dials += tmp;
}
dial.innerHTML = dials;
})();
</script>
</html>
看下效果:
获取当前的时、分、秒数值:
const hourEle = document.getElementById("hour");
const minEle = document.getElementById("min");
const secEle = document.getElementById("sec");
(function (){
const dial = document.getElementById("dial");
let dials = "";
for(let i = 0; i < 60; i++){
let tmp = "";
if(i % 5 === 0){
tmp = `<li style = " width:10px;height:20px;transform:rotate(${6 * i}deg)"></li>`;
}else{
tmp = `<li style = "transform:rotate(${6 * i}deg)"></li>`;
}
dials += tmp;
}
dial.innerHTML = dials;
getTime()
})();
function getTime(){
clearInterval(getTime.timer);
let date = new Date();
let sec = date.getSeconds();
let min = date.getMinutes();
let hour = date.getHours();
// 秒针每秒走6deg
// 分针分钟走6deg
// 时针每小时走30deg
secEle.style.transform = `rotate(${sec * 6}deg)`;
minEle.style.transform = `rotate(${min * 6}deg)`;
hourEle.style.transform = `rotate(${hour * 6}deg)`;
getTime.timer = setInterval(getTime,1000);
}
看下效果:
现在时钟已经动起来了,并可以显示当前的时间。还有一个小问题,就是时钟的分针和时针总是正对着当前分钟的刻度,而实际情况下分针和时针应该是有一些偏移角度的。这是因为我们在计算旋转度数的时候,只单纯计算了当前的分钟或者小时数,正确的做法应该是:
- 计算分针度数时加上当前的秒数(需将秒换算为分)
- 计算时针度数时加上当前的分钟数(需将分换算为时)
对 getTime 函数稍作修改:
...
function getTime(){
clearInterval(getTime.timer);
let date = new Date();
let sec = date.getSeconds();
let min = date.getMinutes();
let hour = date.getHours();
// 秒针每秒走6deg
// 分针分钟走6deg
// 时针每小时走30deg
secEle.style.transform = `rotate(${sec * 6}deg)`;
minEle.style.transform = `rotate(${min * 6 + sec / 60}deg)`;
hourEle.style.transform = `rotate(${hour * 6 + min / 60}deg)`;
getTime.timer = setInterval(getTime,1000);
}
...
看下最终效果:
完。