使用CSS background實現炫酷懸停效果

南城大前端發表於2022-07-05

日常開發過程中,會遇到不少按鈕滑鼠懸停的效果,實現這類懸停效果的方式有很多,藉助偽元素,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%。在懸停時,我們定義--p100%替換初始值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;
}

懸停效果四

這個效果相對於上面的難度較大,更多的用到了圓錐漸變和更多的計算。主要可以分為以下幾個步驟:

  1. 有左右兩個圓錐漸變在元素可視區外
  2. 滑鼠移入增加兩個圓錐漸變的寬度,直到覆蓋元素
  3. 改變整個背景區域的位置,這也是最重要的步驟
  4. 改變後的位置,因為兩個圓錐漸變是同一個顏色,所以視覺上沒有任何變化
  5. 滑鼠移出減小圓錐漸變的寬度,則可以看到反差後的動畫

兩個漸變都需要有預設的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)

參考

background-position 使用百分比值

dry-switching-with-css-variables-the-difference-of-one-declaration

using-percentage-values-with-background-position-on-a-linear-gradient

cool-hover-effects-using-background-properties

相關文章