你所不知道的 CSS 動(dòng)畫技巧與細(xì)節(jié)

怕標(biāo)題起的有點(diǎn)大,下述技巧如果你已經(jīng)掌握了看看就好,歡迎斧正,本文希望通過介紹一些 CSS 不太常用的技巧,輔以一些實(shí)踐,讓讀者可以更加深入的理解掌握 CSS 動(dòng)畫。
廢話少說,直接進(jìn)入正題,本文提到的動(dòng)畫不加特殊說明,皆指 CSS 動(dòng)畫。
正負(fù)旋轉(zhuǎn)相消
嗯。名字起的很奇怪,好像數(shù)學(xué)概念一樣。
在動(dòng)畫中,旋轉(zhuǎn)是非常常用的屬性,
{ transform: rotate(90deg); }
那旋轉(zhuǎn)有一些什么高級(jí)點(diǎn)的技巧呢?當(dāng)然是可以改變 transfrom-origin
,改變旋轉(zhuǎn)中心點(diǎn)啦。
開個(gè)玩笑,改變旋轉(zhuǎn)中心點(diǎn)這個(gè)估計(jì)大家都知道了,這里要介紹的技巧是利用父級(jí)元素正反兩個(gè)方向的旋轉(zhuǎn),來制作一些酷炫的 3d 效果。
首先假設(shè)一下場景,我們有這樣的一層 HTML 結(jié)構(gòu):
<div class="reverseRotate"> <div class="rotate"> <div class="content">正負(fù)旋轉(zhuǎn)相消3D動(dòng)畫</div> </div> </div>
樣式如下:
.content
內(nèi)是我們的主要內(nèi)容,好了,現(xiàn)在想象一下,如果祖先元素 .rotate
進(jìn)行正向 linear 360° 旋轉(zhuǎn),父級(jí)元素 .reverseRotate
進(jìn)行反向 linear 360° 旋轉(zhuǎn),效果回是啥樣?
CSS 代碼如下:
.rotate { animation: rotate 5s linear infinite; } .reverseRotate { animation: reverseRotate 5s linear infinite; } @keyframes rotate { 100% { transform: rotate(360deg); } } @keyframes reverseRotate { 100% { transform: rotate(-360deg); } }
神奇!因?yàn)橐徽环吹男D(zhuǎn),且緩動(dòng)函數(shù)一樣,所以整個(gè) content
看上去依然是靜止的!注意,這里整個(gè) content
靜止的非常重要。
有讀者看到這里就要罵街了,作者你個(gè)智障,靜止了不就沒動(dòng)畫了嗎?哪來的動(dòng)畫技巧?
別急!雖然看上去是靜止的,但是其實(shí)祖先兩個(gè)元素都是在旋轉(zhuǎn)的!這會(huì)看上去風(fēng)平浪靜的效果底下其實(shí)是暗流涌動(dòng)。用開發(fā)者工具選取最外層祖先元素是這樣的:
既然如此,我們繼續(xù)思考,如果我在其中旋轉(zhuǎn)的一個(gè)祖先元素上,添加一些別的動(dòng)畫會(huì)是什么效果?想想就很刺激啊。
為了和文案里面的 3D 動(dòng)畫扯上關(guān)系,我們先給這幾個(gè)元素添加 3D 轉(zhuǎn)換:
div { transform-style: preserve-3d; perspective: 500px; }
接著,嘗試修改上面的旋轉(zhuǎn)動(dòng)畫,在內(nèi)層旋轉(zhuǎn)上額外添加一個(gè) rotateX:
@keyframes rotate { 0% { transform: rotateX(0deg) rotateZ(0deg); } 50% { transform: rotateX(40deg) rotateZ(180deg); } 100% { transform: rotateX(0deg) rotateZ(360deg); } }
效果如下:
Wow,這里需要好好理解一下。由于內(nèi)容 content
層是靜止的但其實(shí)外層兩個(gè)圖層都在旋轉(zhuǎn),通過設(shè)置額外的 rotateX(40deg)
,相當(dāng)于疊加多了一個(gè)動(dòng)畫,由于正反旋轉(zhuǎn)抵消了,所有整個(gè)動(dòng)畫只能看到旋轉(zhuǎn)的 rotateX(40deg)
這個(gè)動(dòng)畫,產(chǎn)生了上述的效果。
CodePen Demo -- Css正負(fù)旋轉(zhuǎn)相消動(dòng)畫
動(dòng)畫相同,緩動(dòng)不同
好的,繼續(xù)下一個(gè)小技巧。
有的時(shí)候我們頁面存在一些具有相同動(dòng)畫的元素,為了讓動(dòng)畫不那么死板,我們可以給相同的動(dòng)畫,賦予不同的緩動(dòng)函數(shù),來達(dá)到動(dòng)畫效果。
假設(shè)我們有如下的結(jié)構(gòu):
<div class="container"> <div class="ball ball1"></div> <div class="ball ball2"></div> <div class="ball ball3"></div> </div>
樣式如下:
我們給它們相同的動(dòng)畫,但是賦予不一樣的緩動(dòng)函數(shù)(animation-timing-function),就像這樣:
.ball1 { animation: move 1s ease-in infinite alternate; } .ball2 { animation: move 1s linear infinite alternate; } .ball3 { animation: move 1s ease-out infinite alternate; } @keyframes move { 100% { transform: translateY(5vw); } }
這樣,一個(gè)簡單的 loading 效果就制作好了。(當(dāng)然這個(gè)技巧比較簡單,學(xué)會(huì)合理運(yùn)用是關(guān)鍵)
CodePen Demo -- 動(dòng)畫相同,緩動(dòng)不同
奇妙的緩動(dòng)
緩動(dòng)函數(shù) timing-function 在動(dòng)畫中占據(jù)了非常重要的地位。
當(dāng)你不想使用 CSS 默認(rèn)提供的 linear
、ease-in
、ease-out
之類緩動(dòng)函數(shù)的,可以自定義 cubic-bezier(1, 1, 0, 0)
,這里有個(gè)非常好用的工具推薦,下面這個(gè)網(wǎng)站,可以方便的調(diào)出你需要的緩動(dòng)函數(shù)并且拿到對(duì)應(yīng)的 cubic-bezier 。
過渡取消
我們?cè)谥谱黜撁娴臅r(shí)候,為了讓頁面更加有交互感,會(huì)給按鈕,陰影,顏色等樣式添加過渡效果,配合 hover 一起使用。
這個(gè)是常規(guī)思維,如果我們的元素一開始是沒有過渡效果,只有 hover 上去才給它添加一個(gè)過渡,又或者一開始元素是有過渡效果的,當(dāng)我們 hover 上去時(shí),取消它的過渡,會(huì)碰撞出什么樣的火花呢?
使用這個(gè)技巧(也許算不上技巧,純粹好玩),我們可以制作出一些有趣的效果,例如下面這個(gè)感覺是利用就 JS 才完成的動(dòng)畫,其實(shí)是純 CSS 動(dòng)畫:
其實(shí)就小圓圈是元素默認(rèn)是帶有 transition
的,只有在 hover 上去的時(shí)候,取消它的過渡,簡單的過程:
- 由于一開始它的顏色的透明的,而 hover 的時(shí)候會(huì)賦予它顏色值,但是由于 hover 時(shí)過渡被取消了,所有它會(huì)直接顯示。
- hover 離開的時(shí)候,它的原本的過渡又回來了,這個(gè)時(shí)候它會(huì)從有顏色到透明值緩慢漸變消失。
可以戳這里感受一下:
CodePen Demo -- Cancle transition
動(dòng)畫層級(jí)的控制,保持動(dòng)畫層級(jí)在最上方
這個(gè)問題可能有一點(diǎn)難理解。需要了解 CSS 動(dòng)畫渲染優(yōu)化的相關(guān)知識(shí)。
先說結(jié)論,動(dòng)畫層級(jí)的控制的意思是盡量讓需要進(jìn)行 CSS 動(dòng)畫的元素的 z-index
保持在頁面最上方,避免瀏覽器創(chuàng)建不必要的圖形層(GraphicsLayer),能夠很好的提升渲染性能。
OK,再一次提到了圖形層(GraphicsLayer),這是一個(gè)瀏覽器渲染原理相關(guān)的知識(shí)(WebKit/blink內(nèi)核下)。
簡單來說,瀏覽器為了提升動(dòng)畫的性能,為了在動(dòng)畫的每一幀的過程中不必每次都重新繪制整個(gè)頁面。在特定方式下可以觸發(fā)生成一個(gè)合成層,合成層擁有單獨(dú)的 GraphicsLayer。
需要進(jìn)行動(dòng)畫的元素包含在這個(gè)合成層之下,這樣動(dòng)畫的每一幀只需要去重新繪制這個(gè) Graphics Layer 即可,從而達(dá)到提升動(dòng)畫性能的目的。
那么一個(gè)元素什么時(shí)候會(huì)觸發(fā)創(chuàng)建一個(gè) Graphics Layer 層?從目前來說,滿足以下任意情況便會(huì)創(chuàng)建層:
- 硬件加速的 iframe 元素(比如 iframe 嵌入的頁面中有合成層)
- 硬件加速的插件,比如 flash 等等
- 使用加速視頻解碼的 元素
- 3D 或者 硬件加速的 2D Canvas 元素
- 3D 或透視變換(perspective、transform) 的 CSS 屬性
- 對(duì)自己的 opacity 做 CSS 動(dòng)畫或使用一個(gè)動(dòng)畫變換的元素
- 擁有加速 CSS 過濾器的元素
- 元素有一個(gè)包含復(fù)合層的后代節(jié)點(diǎn)(換句話說,就是一個(gè)元素?fù)碛幸粋€(gè)子元素,該子元素在自己的層里)
- 元素有一個(gè) z-index 較低且包含一個(gè)復(fù)合層的兄弟元素
本題中說到的動(dòng)畫層級(jí)的控制,原因就在于上面生成層的最后一條:
元素有一個(gè) z-index 較低且包含一個(gè)復(fù)合層的兄弟元素。
這里是存在坑的地方,首先我們要明確兩點(diǎn):
- 我們希望我們的動(dòng)畫得到 GPU 硬件加速,所以我們會(huì)利用類似
transform: translate3d()
這樣的方式生成一個(gè) Graphics Layer 層。 - Graphics Layer 雖好,但不是越多越好,每一幀的渲染內(nèi)核都會(huì)去遍歷計(jì)算當(dāng)前所有的 Graphics Layer ,并計(jì)算他們下一幀的重繪區(qū)域,所以過量的 Graphics Layer 計(jì)算也會(huì)給渲染造成性能影響。
記住這兩點(diǎn)之后,回到上面我們說的坑。
假設(shè)我們有一個(gè)輪播圖,有一個(gè) ul 列表,結(jié)構(gòu)如下:
<div class="container">
<div class="swiper">輪播圖</div>
<ul class="list">
<li>列表li</li>
<li>列表li</li>
<li>列表li</li>
<li>列表li</li>
</ul>
</div>
假設(shè)給他們定義如下 CSS:
.swiper { position: static; animation: 10s move infinite; } .list { position: relative; } @keyframes move { 100% { transform: translate3d(10px, 0, 0); } }
由于給 .swiper
添加了 translate3d(10px, 0, 0)
動(dòng)畫,所以它會(huì)生成一個(gè) Graphics Layer,如下圖所示,用開發(fā)者工具可以打開層的展示,圖形外的黃色邊框即代表生成了一個(gè)獨(dú)立的復(fù)合層,擁有獨(dú)立的 Graphics Layer 。
<
但是!在上面的圖中,我們并沒有給下面的 list
也添加任何能觸發(fā)生成 Graphics Layer 的屬性,但是它也同樣也有黃色的邊框,生成了一個(gè)獨(dú)立的復(fù)合層。
原因在于上面那條元素有一個(gè) z-index 較低且包含一個(gè)復(fù)合層的兄弟元素。我們并不希望 list
元素也生成 Graphics Layer ,但是由于 CSS 層級(jí)定義原因,下面的 list 的層級(jí)高于上面的 swiper,所以它被動(dòng)的也生成了一個(gè) Graphics Layer 。
使用 Chrome,我們也可以觀察到這種層級(jí)關(guān)系,可以看到 .list
的層級(jí)高于 .swiper
:
所以,下面我們修改一下 CSS ,改成:
.swiper { position: relative; z-index: 100; } .list { position: relative; }
這里,我們明確使得 .swiper
的層級(jí)高于 .list
,再打開開發(fā)者工具觀察一下:
可以看到,這一次,.list
元素已經(jīng)沒有了黃色外邊框,說明此時(shí)沒有生成 Graphics Layer 。再看看層級(jí)圖:
此時(shí),層級(jí)關(guān)系才是我們希望看到的,.list
元素沒有觸發(fā)生成 Graphics Layer 。而我們希望需要硬件加速的 .swiper
保持在最上方,每次動(dòng)畫過程中只會(huì)獨(dú)立重繪這部分的區(qū)域。
總結(jié)
- GPU 硬件加速也會(huì)有坑,當(dāng)我們希望使用利用類似 transform: translate3d() 這樣的方式開啟 GPU 硬件加速,一定要注意元素層級(jí)的關(guān)系,盡量保持讓需要進(jìn)行 CSS 動(dòng)畫的元素的 z-index 保持在頁面最上方。
- Graphics Layer 不是越多越好,每一幀的渲染內(nèi)核都會(huì)去遍歷計(jì)算當(dāng)前所有的 Graphics Layer ,并計(jì)算他們下一幀的重繪區(qū)域,所以過量的 Graphics Layer 計(jì)算也會(huì)給渲染造成性能影響。
- 可以使用 Chrome ,用上面介紹的兩個(gè)工具對(duì)自己的頁面生成的 Graphics Layer 和元素層級(jí)進(jìn)行觀察然后進(jìn)行相應(yīng)修改。
- 上面觀察頁面層級(jí)的 chrome 工具非常吃內(nèi)存?好像還是一個(gè)處于實(shí)驗(yàn)室的功能,分析稍微大一點(diǎn)的頁面容易直接卡死,所以要多學(xué)會(huì)使用第一種觀察黃色邊框的方式查看頁面生成的 Graphics Layer 這種方式。
數(shù)字動(dòng)畫
很多技巧單獨(dú)拿出來可能都顯得比較單薄,我覺得最重要的是平時(shí)多積累,學(xué)會(huì)融會(huì)貫通,在實(shí)際項(xiàng)目中靈活組合運(yùn)用,最近項(xiàng)目需要一個(gè)比較富有科技感的數(shù)字計(jì)數(shù)器,展示在線人數(shù)的不斷增加。因?yàn)槭莾?nèi)部需求,沒有設(shè)計(jì)稿,靠前端自由發(fā)揮。
運(yùn)用了上面提到的一些小技巧,參考了一些 CodePen 上的效果,整了個(gè)下述的 3D 數(shù)字計(jì)數(shù)效果,純 CSS 實(shí)現(xiàn),效果圖如下:
總結(jié)
以上所述是小編給大家介紹的你所不知道的 CSS 動(dòng)畫技巧與細(xì)節(jié),希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
- CSS Grid 是一種二維布局系統(tǒng),可以同時(shí)控制行和列,相比 Flex(一維布局),更適合用在整體頁面布局或復(fù)雜模塊結(jié)構(gòu)中,這篇文章主要介紹了前端CSS Grid 布局詳解,需要的朋2025-04-16
CSS Padding 和 Margin 區(qū)別全解析
CSS 中的 padding 和 margin 是兩個(gè)非?;A(chǔ)且重要的屬性,它們用于控制元素周圍的空白區(qū)域,本文將詳細(xì)介紹 padding 和 margin 的概念、區(qū)別以及如何在實(shí)際項(xiàng)目中使用它們2025-04-07- will-change 是一個(gè) CSS 屬性,用于告訴瀏覽器某個(gè)元素在未來可能會(huì)發(fā)生哪些變化,本文給大家介紹CSS will-change 屬性詳解,感興趣的朋友一起看看吧2025-04-07
- 本文給大家分享在 CSS 中,去除a標(biāo)簽(超鏈接)的下劃線的幾種方法,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2025-04-07
- 在前端開發(fā)中,CSS(層疊樣式表)不僅是用來控制網(wǎng)頁的外觀和布局,更是實(shí)現(xiàn)復(fù)雜交互和動(dòng)態(tài)效果的關(guān)鍵技術(shù)之一,隨著前端技術(shù)的不斷發(fā)展,CSS的用法也日益豐富和高級(jí),本文將2025-04-07
css中的 vertical-align與line-height作用詳解
文章詳細(xì)介紹了CSS中的`vertical-align`和`line-height`屬性,包括它們的作用、適用元素、屬性值、常見使用場景、常見問題及解決方案,感興趣的朋友跟隨小編一起看看吧2025-03-26淺析CSS 中z - index屬性的作用及在什么情況下會(huì)失效
z-index屬性用于控制元素的堆疊順序,值越大,元素越顯示在上層,它需要元素具有定位屬性(如relative、absolute、fixed或sticky),本文給大家介紹CSS 中z - index屬性的作用2025-03-21- 文章詳細(xì)介紹了CSS中的打印媒體查詢@mediaprint包括基本語法、常見使用場景和代碼示例,如隱藏非必要元素、調(diào)整字體和顏色、處理鏈接的URL顯示、分頁控制、調(diào)整邊距和背景等2025-03-18
CSS模擬 html 的 title 屬性(鼠標(biāo)懸浮顯示提示文字效果)
本文介紹了如何使用CSS模擬HTML的title屬性,通過鼠標(biāo)懸浮顯示提示文字效果,通過設(shè)置`.tipBox`和`.tipBox.tipContent`的樣式,實(shí)現(xiàn)了提示內(nèi)容的隱藏和顯示,感興趣的朋友一起2025-03-10前端 CSS 動(dòng)態(tài)設(shè)置樣式::class、:style 等技巧(推薦)
本文介紹了Vue.js中動(dòng)態(tài)綁定類名和內(nèi)聯(lián)樣式的兩種方法:對(duì)象語法和數(shù)組語法,通過對(duì)象語法,可以根據(jù)條件動(dòng)態(tài)切換類名或樣式;通過數(shù)組語法,可以同時(shí)綁定多個(gè)類名或樣式,此外2025-02-26