CSS3 中的動畫之 transition 和 transform

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 指定為頁面上的任意一個點柑肴。
布局效果如圖:

時鐘布局效果.png

接下來畫出剩余的其他刻度:

<!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>

看下效果:


js批量生成布局.png

獲取當(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);
}

看下效果:

時鐘效果01.gif

現(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);
}
...

看下最終效果:


時鐘效果02.gif

完。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末淋样,一起剝皮案震驚了整個濱河市耗式,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌趁猴,老刑警劉巖刊咳,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異儡司,居然都是意外死亡娱挨,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門捕犬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來跷坝,“玉大人酵镜,你說我怎么就攤上這事〔褡辏” “怎么了淮韭?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長贴届。 經(jīng)常有香客問我靠粪,道長,這世上最難降的妖魔是什么毫蚓? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任占键,我火速辦了婚禮,結(jié)果婚禮上绍些,老公的妹妹穿的比我還像新娘捞慌。我一直安慰自己,他們只是感情好柬批,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著袖订,像睡著了一般氮帐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洛姑,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天上沐,我揣著相機與錄音,去河邊找鬼楞艾。 笑死参咙,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的硫眯。 我是一名探鬼主播蕴侧,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼两入!你這毒婦竟也來了净宵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤裹纳,失蹤者是張志新(化名)和其女友劉穎择葡,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剃氧,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡敏储,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了朋鞍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片已添。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡妥箕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酝碳,到底是詐尸還是另有隱情矾踱,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布疏哗,位于F島的核電站呛讲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏返奉。R本人自食惡果不足惜贝搁,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芽偏。 院中可真熱鬧雷逆,春花似錦、人聲如沸污尉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽被碗。三九已至某宪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間锐朴,已是汗流浹背兴喂。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留焚志,地道東北人衣迷。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像酱酬,于是被迫代替她去往敵國和親壶谒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 選擇qi:是表達式 標簽選擇器 類選擇器 屬性選擇器 繼承屬性: color岳悟,font佃迄,text-align,li...
    love2013閱讀 2,315評論 0 11
  • HTML5 1.HTML5新元素 HTML5提供了新的元素來創(chuàng)建更好的頁面結(jié)構(gòu): 標簽描述 定義頁面獨立的內(nèi)容區(qū)域...
    L怪丫頭閱讀 2,809評論 0 4
  • 看了很多視頻贵少、文章呵俏,最后卻通通忘記了,別人的知識依舊是別人的滔灶,自己卻什么都沒獲得普碎。此系列文章旨在加深自己的印象,因...
    DCbryant閱讀 1,864評論 0 4
  • 選擇器 CSS3中新添加了很多選擇器录平,解決了很多之前需要用javascript才能解決的布局問題麻车∽褐澹· elemen...
    lovelydong閱讀 483評論 0 2
  • 選擇qi:是表達式 標簽選擇器 類選擇器 屬性選擇器 繼承屬性: color,font动猬,text-align啤斗,li...
    wzhiq896閱讀 1,756評論 0 2