開本系列,談談一些有趣的 CSS
題目,題目類型天馬行空,想到什么說什么,不僅為了拓寬一下解決問題的思路,更涉及一些容易忽視的 CSS 細節。
解題不考慮兼容性,題目天馬行空,想到什么說什么,如果解題中有你感覺到生僻的 CSS 屬性,趕緊去補習一下吧。
不斷更新,不斷更新,不斷更新,重要的事情說三遍。
談談一些有趣的CSS題目(二)-- 從條紋邊框的實現談盒子模型
談談一些有趣的CSS題目(三)-- 層疊順序與堆棧上下文知多少
談談一些有趣的CSS題目(四)-- 從倒影說起,談談 CSS 繼承 inherit
談談一些有趣的CSS題目(五)-- 單行居中,兩行居左,超過兩行省略
談談一些有趣的CSS題目(六)-- 全兼容的多列均勻布局問題
談談一些有趣的CSS題目(八)-- 純CSS的導航欄Tab切換方案
談談一些有趣的CSS題目(九)-- 巧妙的實現 CSS 斜線
談談一些有趣的CSS題目(十一)-- reset.css知多少
談談一些有趣的CSS題目(十二)-- 深入探討 CSS 特性檢測 @supports 與 Modernizr
所有題目匯總在我的 Github 。
正文從這里開始。有的時候,嗯,應該說某些特定場合,我們可能需要下面這樣的動畫效果,漸變 + animation :
假設我們漸變的寫法如下:
div { background: linear-gradient(90deg, #ffc700 0%, #e91e1e 100%); }
按照常規想法,配合 animation
,我們首先會想到在 animation
的步驟中通過改變顏色實現顏色漸變動畫,那么我們的 CSS 代碼可能是:
div { background: linear-gradient(90deg, #ffc700 0%, #e91e1e 100%); animation: gradientChange 2s infinite; } @keyframes gradientChange { 100% { background: linear-gradient(90deg, #e91e1e 0%, #6f27b0 100%); } }
上面我們用到了三種顏色:
#ffc700
黃色#e91e1e
紅色#6f27b0
紫色
最后,並沒有我們預期的結果,而是這樣的:
也就是說,線性漸變是不支持動畫 animation
的,那單純的由一個顏色,變化到另外一個顏色呢?像下面這樣:
div { background: #ffc700; animation: gradientChange 3s infinite alternate; } @keyframes gradientChange { 100% { background: #e91e1e; } }
發現,單純的單色值是可以發生漸變的:
So
總結一下,線性漸變(徑向漸變)是不支持 animation
的,單色的 background 是支持的。
查找了下文檔,在 background
附近區域截圖如下:
哪些 CSS 屬性可以動畫?,上面的截圖是不完整的支持 CSS 動畫的屬性,完整的可以戳左邊。
對於 background
相關的,文檔里寫的是支持 background
但是沒有細說不支持 background: linear-gradient()/radial-gradient()
。猜測原因,可能是由於漸變中加入 animation 的變化對過於消耗性能。
那么是否我們想要的背景色漸變動畫就無法實現了呢?下面我們就發散下思維看看有沒有其他方式可以達到我們的目標。
通過 background-position 模擬漸變動畫
上面哪些 CSS 屬性可以動畫的截圖中,列出了與 background
相關還有 background-position
,也就是 background-position
是支持動畫的,通過改變 background-position
的方式,可以實現漸變動畫:
div { background: linear-gradient(90deg, #ffc700 0%, #e91e1e 50%, #6f27b0 100%); background-size: 200% 100%; background-position: 0 0; animation: bgposition 2s infinite linear alternate; } @keyframes bgposition { 0% { background-position: 0 0; } 100% { background-position: 100% 0; } }
這里我們還配合了 background-size
。首先了解下:
background-position
:指定圖片的初始位置。這個初始位置是相對於以background-origin
定義的背景位置圖層來說的。
background-size
:設置背景圖片大小。當取值為百分比時,表示指定背景圖片相對背景區的百分比大小。當設置兩個參數時,第一個值指定圖片的寬度,第二個值指定圖片的高度。
通過 background-size: 200% 100%
將圖片的寬度設置為兩倍背景區的寬度,再通過改變 background-position
的 x 軸初始位置來移動圖片,由於背景圖設置的大小是背景區的兩倍,所以 background-position
的移動是由 0 0
-> 100% 0
。最終效果如下:
通過 background-size 模擬漸變動畫
既然 background-position
可以,那么另一個 background-size
當然也是不遑多讓。與上面的方法類似,只是這次 background-position
輔助 background-size
,CSS 代碼如下:
div { background: linear-gradient(90deg, #ffc700 0%, #e91e1e 33%, #6f27b0 66%, #00ff88 100%); background-position: 100% 0; animation: bgSize 5s infinite ease-in-out alternate; } @keyframes bgSize { 0% { background-size: 300% 100%; } 100% { background-size: 100% 100%; } }
效果如下:
通過改變 background-size
的第一個值,我將背景圖的大小由 3 倍背景區大小向 1 倍背景區大小過渡,在背景圖變換的過程中,就有了一種動畫的效果。
而至於為什么要配合 background-position: 100% 0
。是由於如果不設置 background-position
,默認情況下的值為 0% 0%
,會導致動畫最左側的顏色不變,像下面這樣,不大自然:
通過 transform 模擬漸變動畫
上面兩種方式雖然都可以實現,但是總感覺不夠自由,或者隨機性不夠大。
不僅如此,上述兩種方式,由於使用了 background-position
和 background-size
,並且在漸變中改變這兩個屬性,導致頁面不斷地進行大量的重繪(repaint),對頁面性能消耗非常嚴重,所以我們還可以試試 transfrom
的方法:
使用偽元素配合 transform
進行漸變動畫,通過元素的偽元素 before
或者 after
,在元素內部畫出一個大背景,再通過 transform
對偽元素進行變換:
div { position: relative; overflow: hidden; width: 180px; height: 180px; &::before { content: ""; position: absolute; top: -100%; left: -100%; bottom: -100%; right: -100%; background: linear-gradient(45deg, #ffc700 0%, #e91e1e 50%, #6f27b0 100%); background-size: 100% 100%; animation: bgposition 8s infinite linear alternate; z-index: -1; } } @keyframes bgposition { 0% { transform: translate(30%, 30%); } 25% { transform: translate(30%, -30%); } 50% { transform: translate(-30%, -30%); } 75% { transform: translate(-30%, 30%); } 100% { transform: translate(30%, 30%); } }
實現原理如下圖所示:
我們可以在任意 animation
動畫過程中再加入 scale
、skew
、roate
等變換,讓效果看上去更加逼真隨機。效果如下:
上面列出來的只是部分方法,理論而言,偽元素配合能夠產生位移或者形變的屬性都可以完成上面的效果。我們甚至可以運用不同的緩動函數或者借鑒蟬原則,制作出隨機性十分強的效果。
當然,本文羅列出來的都是純 CSS 方法,使用 SVG 或者 Canvas 同樣可以制作出來,而且性能更佳。感興趣的讀者可以自行往下研究。
運用背景色漸變動畫
背景色漸變動畫具體可以運用在什么地方呢,稍微舉個例子。
背景色漸變過渡實現按鈕的明暗變化
效果如下:
除此之外,在背景板凸顯文字,讓一些靜態底圖動起來吸引眼球等地方都有用武之地。
到此本文結束,如果還有什么疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。