最近專案中 Ant Design 接入比較多,還是非常不錯的。不知道大家有沒有發現這樣的效果,在官網上,如果滑鼠放在Logo上,字母i
上的圖示會不停的變化,離開後停止,放上去重新變化,算得上是一個小彩蛋(可能我之前沒發現?),演示如下:
不過沒發現也不意外,因為這個效果是 js 實現的,必須等待載入完成才能生效,而官網有時候又特別的慢,比如像這種還在載入的情況下,大概率是不會有以上的hover
效果的
嗯,思考了一下,這種效果完全可以用純 CSS 來完成呀,實現成本又低,又能有效避免上述的載入問題,一起看看吧
一、CSS 實現原理
整個實現原理大致如下
- 準備一個包含所有小圖示的素材
- 建立一個改變背景位置的CSS逐幀動畫
- 通過滑鼠 hover 來控制動畫執行
二、素材準備
為了避免多次請求,也為了方便建立動畫,這裡把所有小圖示素材組合在一塊(從官網另存下來的),就像以前的“雪碧圖”一樣,如下
假設 HTML 結構是這樣的
<h1 class="logo">Ant Design</h1>
為了更好的語義化,這裡的文字建議保留,然後通過其他方式隱藏文字(比如透明度),可以將 logo 作為背景圖片,然後可變化的小圖示用偽元素生成(裝飾性的元素都可以用偽元素來生成,保證HTML的整潔),CSS 如下
.logo{
width: 500px;
height: 100px;
position: relative;
color: transparent;
background: url('https://imgservices-1252317822.image.myqcloud.com/image/012420220165011/c0e82c29.svg') center/contain no-repeat;
cursor: pointer;
}
.logo::after{
content: '';
position: absolute;
width: 32px;
height: 32px;
background: url('https://imgservices-1252317822.image.myqcloud.com/image/012420220165415/b0005044.svg') 0 / cover no-repeat;
right: 113px;
top: -18px;
}
靜態佈局就算出來了
二、CSS 逐幀動畫
然後是動畫,只需要利用 CSS 動畫函式中的 steps() 功能符,就可以實現逐幀動畫
首先定義一個關鍵幀,改變背景位置就行了
@keyframes random {
to {
background-position: 100%;
}
}
這裡小圖示總共有 11 張,相互之間的變化就是 10 步,所以動畫設定如下
.logo::after{
/*其他樣式*/
animation: random 1s steps(10) infinite;
}
這樣就得到了一個無限迴圈的逐幀動畫
三、CSS動畫的暫停與執行
預設情況下,CSS動畫是預設執行的,但是現在的需求是,只有滑鼠 hover
上去才會動起來。
可能有同學會這樣做,預設情況下沒有動畫,hover 的時候建立動畫,如下
.logo::after{
/*預設無動畫*/
}
.logo:hover::after{
animation: random 1s steps(10) infinite;
}
但是這樣做會有兩個問題:
- 每次實時建立動畫會有更多的效能消耗
- 每次滑鼠離開後位置就還原成初始狀態了
因此,這種方式並不可取
除了上述方式可以控制動畫執行之外,還可以通過animation-play-state
主動設定暫停,如下
.logo::after{
/*其他樣式*/
animation: random 1s steps(10) infinite;
animation-play-state: paused; /*動畫暫停*/
}
這樣下來,預設就不會動了,然後在hover
的時候“執行”就行了
.logo:hover::after{
animation-play-state: running; /*動畫執行*/
}
效果如下
四、指定初始位置
現在預設是小圖示是第一個,如果想指定另外一個,比如❤
這種情況如何處理呢
首先我們想到,可以手動改變背景位置就行了,❤ 在第8個,所以
.logo::after{
/*其他樣式*/
background-position: -224px; /* 32 * 7 */
}
效果如下
這樣下來,問題更多,由於改變了動畫的起始位置,動畫從第 8 個的地方運動到最右側,左邊的都不經過了,step 也需要重新調整。
除了這種方式,還可以通過動畫的“負延遲”來實現,給動畫新增一個負的延遲後,動畫會提前運動到未來位置。
比如這裡想指定到未來第7幀的位置,就可以延遲負的總運動時長的 7/ 10 ,實現如下
.logo::after{
/*其他樣式*/
animation-delay: -.7s; /* 7 / 10 * 1s*/
}
這樣就不會影響原有的動畫了,完美實現
完整程式碼可以訪問:Ant Design Logo (codepen.io)
附上完整程式碼(最近codepen貌似不太穩定)
.logo{
width: 500px;
height: 100px;
position: relative;
color: transparent;
background: url('https://imgservices-1252317822.image.myqcloud.com/image/012420220165011/c0e82c29.svg') center/contain no-repeat;
cursor: pointer;
}
.logo::after{
content: '';
position: absolute;
width: 32px;
height: 32px;
background: url('https://imgservices-1252317822.image.myqcloud.com/image/012420220165415/b0005044.svg') 0 / cover no-repeat;
right: 113px;
top: -18px;
animation: random 1s -.7s steps(10) infinite;
animation-play-state: paused;
}
.logo:hover::after{
animation-play-state: running;
}
@keyframes random {
to {
background-position: 100%;
}
}
五、總結和說明
上面就是針對 Ant Design 官網 Logo 效果的 CSS 實現,程式碼量非常少,而且也避免了 js 未載入完成時的問題,體驗更好,下面簡單總結一下
- CSS 渲染是及時的,只要頁面可見,就不會影響 CSS 互動
- 逐幀動畫可以通過 CSS 動畫 中的 step() 函式實現
- CSS 動畫可以自動執行,也可以手動暫停
- 通過設定負的延時,可以讓 CSS 動畫提前執行
當然,CSS 的優點還不只這些,開啟 Ant Design 控制檯,讓我有點崩潰的是,居然是不斷更換svg
連結實現的,如果一直放在 Logo 上就會源源不斷的請求圖片,小圖示也會出現“閃爍”的情況
這個請求量就有點驚人了。如果有負責 Ant Design 官網的小夥伴看到這裡,是不是可以優化一下呢?
最後,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉發❤❤❤