CSS3 使運動變得更加簡單了齐疙,我們只需用少量的代碼债热,就可以寫出數(shù)行甚至更多 JavaScript 代碼的效果,并且 CSS3 處理諸如旋轉(zhuǎn)抡砂、傾斜大咱、3D 等效果的能力是遠強于 JavaScript 的。你能用 JavaScript 讓一個 div 渲染任意角度嗎注益?也許能碴巾,但復(fù)雜度肯定超乎想象,而這個效果可以使用 CSS3 一個函數(shù)輕松搞定丑搔。
有了 CSS3 寫動畫厦瓢,就可以完全拋棄 JavaScript 了嗎?當(dāng)然不是啤月。CSS3 強在表現(xiàn)煮仇,JavaScript 強在邏輯,二者結(jié)合可以發(fā)揮最大的威力谎仲。
CSS3 中實現(xiàn)動畫效果可能會用到這幾個屬性:
- transition
- transform
- animation
這幾個屬性構(gòu)成了 CSS3 豐富多彩的動畫世界浙垫。
transition
這是 CSS3 的一個屬性,意為過渡郑诺。該屬性用在某個元素上夹姥,用來定義該元素的屬性發(fā)生變化時,呈現(xiàn)出的過渡效果间景。
transition 有幾個屬性值:
- transition-property:需要應(yīng)用過渡效果的屬性名稱
- transition-duration:完成該過渡效果所需的時間
- transition-timing-function:過渡效果
- transition-delay:延遲時間(默認為 0)
transition-timing-function 有下列可選值:
- linear:勻速過渡
- ease:先慢后快再慢過渡
- ease-in:先慢后快過渡
- ease-out:先快后慢過渡
- ease-in-out:先慢后快再慢過渡
- cubic-bezier:根據(jù)貝賽爾曲線過渡
這系列規(guī)則可以合寫為:
transiton:<transition-property> <transition-duration> <transition-timing-function> <transition-delay>
如果想根據(jù)屬性定義不同的過渡佃声,可以這樣寫(以寬高為例):
transition:width 1s ease-in,height 0.5s ease-out 1s;
貝賽爾曲線用來定義更加復(fù)雜的過渡,如果我們想要一個自定義的過渡效果倘要,就可以使用貝塞爾曲線圾亏,這個網(wǎng)站可以將貝塞爾曲線轉(zhuǎn)換為相應(yīng)的 CSS3 函數(shù)十拣,推薦使用。
關(guān)于這些屬性的記憶志鹃,這里給出了一個羞羞的方式夭问。
transitionend 事件
transitionend 事件是在過渡效果完成后觸發(fā)
ele.addEventListener("transitionend",fun);
注:元素的每個屬性過渡完成后都會觸發(fā)一次 transitionend 事件。
transform
transform 用來對元素進行 2D/3D 上的屬性轉(zhuǎn)換曹铃。簡單說來缰趋,使用該屬性,可以對物體上進行形狀上的變化陕见,如傾斜秘血,旋轉(zhuǎn)∑捞穑可以讓物體在 2D 或者 3D 空間下展示灰粮,讓物體在空間中進行位移等。常用的有這么些屬性:
- scale:對元素進行縮放
- rotate:對元素進行旋轉(zhuǎn)
- skew:對元素進行傾斜變換
- translate:對元素進行位移
- scale3d:3D 場景下縮放
- rotate3d:3D 場景下旋轉(zhuǎn)
- skew3d:3D 場景下傾斜
- translate3d:3D 場景下位移
詳細的用法可以參考這里忍坷。
下面是一個動態(tài)時鐘的例子粘舟。
動態(tài)時鐘
先來看下布局:
<!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>
看下效果:
獲取當(dāng)前的時、分旬薯、秒數(shù)值:
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);
}
看下效果:
現(xiàn)在時鐘已經(jīng)動起來了晰骑,并可以顯示當(dāng)前的時間。還有一個小問題袍暴,就是時鐘的分針和時針總是正對著當(dāng)前分鐘的刻度些侍,而實際情況下分針和時針應(yīng)該是有一些偏移角度的。這是因為我們在計算旋轉(zhuǎn)度數(shù)的時候政模,只單純計算了當(dāng)前的分鐘或者小時數(shù)岗宣,正確的做法應(yīng)該是:
- 計算分針度數(shù)時加上當(dāng)前的秒數(shù)(需將秒換算為分)
- 計算時針度數(shù)時加上當(dāng)前的分鐘數(shù)(需將分換算為時)
對 getTime 函數(shù)稍作修改:
...
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);
}
...
看下最終效果:
完。