日常開發過程中,會遇到不少按鈕滑鼠懸停的效果,實現這類懸停效果的方式有很多,藉助偽元素,CSS3變換及過渡等都可以實現。今天的文章將使用背景色實現類似的效果,當我們遇到一個問題時,你的腦海中的方案不止一種時,我想這肯定是極好的,使用不同的方法達到同一的效果,或者某天所遇到的問題就迎刃而解了。
今天主要實現的滑鼠懸停效果如下GIF圖所示。
懸停效果一
上圖所示的效果程式碼如下所示,只需要4行程式碼即可實現效果,是否很驚訝程式碼為何如此精簡,接下來將詳細說明是如何做到的。
.hover-1 {
background: linear-gradient(#1095c1 0 0) var(--p, 0) / var(--p, 0) no-repeat;
transition: .4s, background-position 0s;
}
.hover-1:hover {
--p: 100%;
color: #fff;
}
首先,我們從一個簡單的background-size
過渡開始,如上圖所示,背景色的高度是一直保持100%,我們只需要改變其寬度從0%到100%之間的切換。因為使用了background-size
改變寬度,所以使用 background-image: linear-gradient
設定背景色。因為只有一個顏色值,使用此#1095c1 0 0
簡寫方式,不需要寫兩個色值。
background-image: linear-gradient(#1095c1 0 0);
使用background-size時,我們可以省略高度,因為預設情況下漸變是全高。我們使用background-size: 0
過渡到background-size: 100%
。
.hover-1 {
background-size: 0;
}
.hover-1:hover {
background-size: 100%;
}
進一步優化,引入一個自定義屬性以避免重複background-size
,--p
最初沒有定義,因此將使用0%
。在懸停時,我們定義--p
為100%
替換初始值0%
.hover-1 {
background-size: var(--p, 0%);
}
.hover-1:hover {
--p: 100%;
}
到此我們的效果如下所示
接下來引入background-position
實現反轉的效果,看最開始的GIF圖可以分開2步完成。
- 滑鼠懸停時背景是從右往左增加尺寸
- 滑鼠移出時背景是從左往右減小尺寸
並且在懸停時不能增加transition
過渡動畫,此屬性是需要及時生效的,所以增加了background-position 0s
。
.hover-1 {
background-position: left;
transition: .4s,background-position 0s;
}
.hover-1:hover {
--p: 100%;
background-position: right;
}
還可以進一步優化,background-position
的值使用百分比。
.hover-1 {
background-position: 0%;
transition: .4s,background-position 0s;
}
.hover-1:hover {
--p: 100%;
background-position: 100%;
}
聰明的你可能已經發現了,懸停時的兩個值都是100%,那麼我們可以進一步優化都使用自定義屬性--p
。
.hover-1 {
background: linear-gradient(#1095c1 0 0) no-repeat;
transition: .4s,background-position 0s;
background-size: var(--p, 0%);
background-position: var(--p, 0%);
}
.hover-1:hover {
--p: 100%;
}
針對 background
我們使用複合寫法,進一步精簡程式碼,使用 /
做分割,前面是 background-position
後面是 background-size
。
.hover-1 {
background: linear-gradient(#1095c1 0 0) var(--p, 0%) / var(--p,0%) no-repeat;
transition: .4s, background-position 0s;
}
.hover-1:hover {
--p: 100%;
}
到此就完整的實現懸停效果一且精簡了程式碼,基於此設計,還可以稍微改動程式碼讓懸停效果達到相反的效果,修改background-position
從100% 到 0%,而不是上面的 0% 到 100%。為了保持 --p
自定義屬性不變,我們使用calc()
函式處理。
background: linear-gradient(#1095c1 0 0) calc(100% - var(--p,0%)) / var(--p,0%) no-repeat;
懸停效果二
如上圖所示,相比較效果一更為複雜,整個效果是由多個動畫步驟組成。最開始的背景區域在可視區域之外,從左往右移動到覆蓋到整個元素底部,然後改變背景色到高度到100%覆蓋到整個元素。
這裡需要使用到background-position
的百分比使用方式,不理解其使用方式的話可以看看文末的參考文章。訣竅是將寬度改為200%,但不用擔心背景色超出後的溢位問題,對於元素溢位的背景色都是隱藏的,程式碼如下。
.hover-2 {
background-image: linear-gradient(#1095c1 0 0);
background-size: 200% .08em;
background-position: 200% 100%;
background-repeat: no-repeat;
transition: background-size .3s, background-position .3s .3s;
}
.hover-2:hover {
transition: background-size .3s .3s, background-position .3s;
background-size: 200% 100%;
background-position: 100% 100%;
}
然後繼續開始優化程式碼,首先使用background
的複合寫法精簡,減少額外的宣告。
.hover-2 {
background:
linear-gradient(#1095c1 0 0) no-repeat
var(--p, 200%) 100% / 200% var(--p, .08em);
transition: .3s var(--t, 0s), background-position .3s calc(.3s - var(--t, 0s));
}
.hover-2:hover {
--p: 100%;
--t: .3s;
}
這裡增加一個自定義變數--t
,在滑鼠懸停時,我們設定為.3s,最終程式碼如下:
transition: .3s .3s, background-position .3s 0s;
滑鼠移出時,--t
未定義,最終程式碼如下:
transition: .3s 0s, background-position .3s .3s;
到此為止,滑鼠懸停時宣告瞭兩個變數,我們還可以進一步優化,通過一個屬性更新多個屬性,關於如何生成這樣的程式碼可以看文末的參考連結,最終程式碼修改如下:
.hover-2 {
background:
linear-gradient(#1095c1 0 0) no-repeat
calc(200% - var(--i, 0) * 100%) 100% / 200% calc(100% * var(--i, 0) + .08em);
transition: .3s calc(var(--i, 0) * .3s), background-position .3s calc(.3s - calc(var(--i, 0) * .3s));
}
.hover-2:hover {
--i: 1;
}
--i
最終是未定義則是0,懸停時更新為1,該變數就如同在JS中的一個開關變數,到此為止,整個效果只需要三行css宣告完成。
懸停效果三
此效果在效果二的基礎上擴充套件為兩個漸變動畫效果,最初會有兩個漸變溢位的元素,預設都不在視野範圍內,每一個的寬度為整個元素的一半。當我們滑鼠移入的時候修改這兩個溢位的元素到可見區域,第一個漸變位於左下角,第二個漸變位於右上角,最後增加高度覆蓋到整個元素。
初始CSS程式碼如下,與效果二的程式碼幾乎相同,唯一的區別就是具有兩個不同的位置同時發生動畫效果,這裡同樣用到了百分比的background-position
。
.hover-3 {
background-image:
linear-gradient(#1095c1 0 0),
linear-gradient(#1095c1 0 0);
background-repeat: no-repeat;
background-size: 50% .08em;
background-position:
-100% 100%,
200% 0;
transition: background-size .3s, background-position .3s .3s;
}
.hover-3:hover {
background-size: 50% 100%;
background-position:
0 100%,
100% 0;
transition: background-size .3s .3s, background-position .3s;
}
接下來開始優化程式碼,background
複合寫法,自定義屬性以及calc()進一步整理,這裡新增了一個額外的--c自定義屬性,因為在background
中用到了兩次。
.hover-3 {
--c: no-repeat linear-gradient(#1095c1 0 0);
background:
var(--c) calc(-100% + var(--p, 0%)) 100% / 50% var(--p, .08em),
var(--c) calc( 200% - var(--p, 0%)) 0 / 50% var(--p, .08em);
transition: .3s var(--t, 0s), background-position .3s calc(.3s - var(--t, 0s));
}
.hover-3:hover {
--p: 100%;
--t: 0.3s;
}
接下來使用開關變數進一步優化,只有一個變數--i
.hover-3 {
--c: no-repeat linear-gradient(#1095c1 0 0);
background:
var(--c) calc(-100% + var(--i, 0) * 100%) 100% / 50% calc(100% * var(--i, 0) + .08em),
var(--c) calc( 200% - var(--i, 0) * 100%) 0 / 50% calc(100% * var(--i, 0) + .08em);
transition: .3s calc(var(--i, 0) * .3s), background-position .3s calc(.3s - var(--i, 0) * .3s);
}
.hover-3:hover {
--i: 1;
}
懸停效果四
這個效果相對於上面的難度較大,更多的用到了圓錐漸變和更多的計算。主要可以分為以下幾個步驟:
- 有左右兩個圓錐漸變在元素可視區外
- 滑鼠移入增加兩個圓錐漸變的寬度,直到覆蓋元素
- 改變整個背景區域的位置,這也是最重要的步驟
- 改變後的位置,因為兩個圓錐漸變是同一個顏色,所以視覺上沒有任何變化
- 滑鼠移出減小圓錐漸變的寬度,則可以看到反差後的動畫
兩個漸變都需要有預設的0寬度和兩倍的元素高度(0% 200%),每個漸變的配置如下圖所示:
background-image:
conic-gradient(from -135deg at 100% 50%, var(--c) 90deg, #0000 0),
conic-gradient(from -135deg at 1.2em 50%, #0000 90deg, var(--c) 0);
視覺上,每個漸變的寬度都是元素的一半,但是實際上並不止,因為有錐形的空隙。所以需要在一半寬度的基礎上額外增加一定的數值,這個值可以大一點,以便覆蓋到整個元素。
.hover-4:hover {
background-size: calc(50% + .6em) 200%;
}
優化後的程式碼如下:
.hover-4 {
--c: #1095c1;
line-height: 1.2em;
background:
conic-gradient(from -135deg at 100% 50%, var(--c) 90deg, #0000 0)
0 var(--p, 0%) / var(--s, 0%) 200% no-repeat,
conic-gradient(from -135deg at 1.2em 50%, #0000 90deg, var(--c) 0)
100% var(--p, 0%) / var(--s, 0%) 200% no-repeat;
transition: .4s, background-position 0s;
}
.hover-4:hover {
--p: 100%;
--s: calc(50% + .6em);
}
總結
以上總共分析了四種懸停效果,雖然效果不同,但主要都用到了 CSS background
屬性、自定義屬性和calc()
,不同的組合情況製作出來不同的效果,但是最後的程式碼都是類似,最終有了極其簡潔可維護的程式碼。基於此,這只是冰山一角,現代CSS的強大還可以產出各種神奇的效果。你是否有想法來試試呢~
看到最後如果覺得有用,點贊,關注,收藏起來吧,說不定哪天就用上啦~
專注前端開發,分享前端相關技術乾貨,公眾號:南城大前端(ID: nanchengfe)
參考
dry-switching-with-css-variables-the-difference-of-one-declaration
using-percentage-values-with-background-position-on-a-linear-gradient