[譯]使用 CSS 實現具備方面感知的幽靈按鈕

  • Ghost Buttons:幽靈按鈕是指具有基本的按鈕形狀的透明按鈕,有細實線的邊框。在懸停時背景填充顏色以突出按鈕。
  • direction aware:方向感知這裏主要說的是可以判斷鼠標是從按鈕哪一個方向過來的。

本文中,咱們將構建一個幽靈按鈕,實現按鈕很簡單,但有趣而棘手的部分是使按鈕背景色從鼠標進入的方向開始填充。css

下面是咱們完成的一個按鈕!html

codepen-demoweb

多數狀況下,鼠標懸停時,咱們是把 background-color 過渡顯示成與邊框顏色同樣。在某些設計中,按鈕可能會從左到右,從上到下等填充,以加強視覺效果。以下例,從左到右填充:測試

codepen-demo動畫

若是咱們把鼠標從按鈕右側放上,而填充是從左側開始,咱們就會感受體驗很差!ui

若是按鈕從咱們的懸停點開始填充,體驗效果會更好。spa

怎麼才能使按鈕具備方向感知性呢?咱們首先想到的多是使用 JavaScript 來實現,但咱們也能夠經過 CSS 配合一些標籤來實現。設計

下面咱們能夠先看看最終實現的效果:3d

codepen-democode

接下來,咱們把實現步驟分解開來。

基礎

咱們先建立一個按鈕,很簡單!

<button>Boo!</button>
複製代碼

咱們使用 CSS 自定義屬性完成樣式,這樣更易於維護。

button {
  --borderWidth: 5;
  --boxShadowDepth: 8;
  --buttonColor: #f00;
  --fontSize: 3;
  --horizontalPadding: 16;
  --verticalPadding: 8;

  background: transparent;
  border: calc(var(--borderWidth) * 1px) solid var(--buttonColor);
  box-shadow: calc(var(--boxShadowDepth) * 1px) calc(var(--boxShadowDepth) * 1px) 0 #888;
  color: var(--buttonColor);
  cursor: pointer;
  font-size: calc(var(--fontSize) * 1rem);
  font-weight: bold;
  outline: transparent;
  padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px);
  transition: box-shadow 0.15s ease;
}

button:hover {
  box-shadow: calc(var(--boxShadowDepth) / 2 * 1px) calc(var(--boxShadowDepth) / 2 * 1px) 0 #888;
}

button:active {
  box-shadow: 0 0 0 #888;
}
複製代碼

codepen-demo

咱們實現了一個按鈕及懸停效果,可是沒有填充。咱們繼續進行!

添加填充

咱們額外建立元素作爲按鈕填充時的狀態。經過 clip-path 將它隱藏。當鼠標懸停在按鈕上時設置 clip-path 將元素過渡顯示出來。

它們必須與父按鈕對齊。這裏咱們的 CSS 變量會顯示出它的優點。

原本咱們能夠經過僞元素實現,可是它不知足咱們須要的四個方面,並且它還會干擾可訪問性…稍後咱們再講。

咱們先添加一個從左到右填充的效果。首頁咱們要添加一個 span 標籤,它與按鈕具備相同的內容。

<button>Boo!
  <span>Boo!</span>
</button>
複製代碼

下面咱們要將 span 與按鈕重疊對齊。

button span {
  background: var(--buttonColor);
  border: calc(var(--borderWidth) * 1px) solid var(--buttonColor);
  bottom: calc(var(--borderWidth) * -1px);
  color: var(--bg, #fafafa);
  left: calc(var(--borderWidth) * -1px);
  padding: calc(var(--verticalPadding) * 1px) calc(var(--horizontalPadding) * 1px);
  position: absolute;
  right: calc(var(--borderWidth) * -1px);
  top: calc(var(--borderWidth) * -1px);
}
複製代碼

最後,咱們經過裁剪使元素隱藏,當懸停時更新裁剪規則使元素顯示出來。

button span {
  --clip: inset(0 100% 0 0);
  -webkit-clip-path: var(--clip);
  clip-path: var(--clip);
  transition: clip-path 0.25s ease;
  // ...Remaining div styles
}

button:hover span {
  --clip: inset(0 0 0 0);
}
複製代碼

codepen-demo

添加方向感知

那麼,如何感知方向呢?咱們須要四個要素。每一個元素將負責檢測懸停入口點。使用 clip-path,咱們能夠將按鈕區域分爲四個部分。

咱們在按鈕裏添加四個 span,並放在四個方面以進行填充按鈕。

<button>
  Boo!
  <span></span>
  <span></span>
  <span></span>
  <span></span>
</button>
複製代碼
button span {
  background: var(--bg);
  bottom: calc(var(--borderWidth) * -1px);
  -webkit-clip-path: var(--clip);
  clip-path: var(--clip);
  left: calc(var(--borderWidth) * -1px);
  opacity: 0.5;
  position: absolute;
  right: calc(var(--borderWidth) * -1px);
  top: calc(var(--borderWidth) * -1px);
  z-index: 1;
}
複製代碼

咱們將每一個元素進行定位並使用 CSS 變量賦予它們背景色及裁剪規則。

button span:nth-of-type(1) {
  --bg: #00f;
  --clip: polygon(0 0, 100% 0, 50% 50%, 50% 50%);
}
button span:nth-of-type(2) {
  --bg: #f00;
  --clip: polygon(100% 0, 100% 100%, 50% 50%);
}
button span:nth-of-type(3) {
  --bg: #008000;
  --clip: polygon(0 100%, 100% 100%, 50% 50%);
}
button span:nth-of-type(4) {
  --bg: #800080;
  --clip: polygon(0 0, 0 100%, 50% 50%);
}
複製代碼

爲了測試,懸停時咱們改變一下元素的透明度。

button span:nth-of-type(1):hover,
button span:nth-of-type(2):hover,
button span:nth-of-type(3):hover,
button span:nth-of-type(4):hover {
  opacity: 1;
}
複製代碼

哎呀,這裏有個問題。若是咱們進入並懸停一個分段,而後懸停在另外一分段上,則填充方向將會發生變化。這看起來很不對勁。要解決此問題,咱們能夠在懸停時設置 z-indexclip-path 來填充這一空間。

button span:nth-of-type(1):hover,
button span:nth-of-type(2):hover,
button span:nth-of-type(3):hover,
button span:nth-of-type(4):hover {
  --clip: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  opacity: 1;
  z-index: 2;
}
複製代碼

codepen-demo

合到一塊兒

如今咱們知道如何建立填充動畫了,也知道如何判斷方向了。那咱們應該如何將它們放到一塊兒實現想要的效果呢?答案是同級選擇器!

當咱們將鼠標懸停在一方向塊上時,咱們能夠填充指定的元素。

首先,咱們要更新一下咱們的代碼:

<button>
  Boo!
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <b>Boo!</b>
  <b>Boo!</b>
  <b>Boo!</b>
  <b>Boo!</b>
</button>
複製代碼

接下來,咱們須要更新一下咱們的 CSS,填充樣式咱們能夠複用從左到右的樣式。但須要爲每一個元素設置不一樣的 clip-path。咱們按第一個在上,第二個在右,第三個在下,第四個在左的順序設置。

button b:nth-of-type(1) {
  --clip: inset(0 0 100% 0);
}
button b:nth-of-type(2) {
  --clip: inset(0 0 0 100%);
}
button b:nth-of-type(3) {
  --clip: inset(100% 0 0 0);
}
button b:nth-of-type(4) {
  --clip: inset(0 100% 0 0);
}
複製代碼

最後一步是鼠標懸停在對應方向塊時更新對應元素的 clip-path

button span:nth-of-type(1):hover ~ b:nth-of-type(1),
button span:nth-of-type(2):hover ~ b:nth-of-type(2),
button span:nth-of-type(3):hover ~ b:nth-of-type(3),
button span:nth-of-type(4):hover ~ b:nth-of-type(4) {
  --clip: inset(0 0 0 0);
}
複製代碼

至此,咱們具備方向感知性的幽靈按鈕就實現了。

codepen-demo

可訪問性

當按鈕不可訪問裏,會顯示以下狀態。

這些額外的元素使屏幕閱讀器重複閱讀了四次。因此,咱們須要將它們隱藏起來。

<button>
  Boo!
  <span></span>
  <span></span>
  <span></span>
  <span></span>
  <b aria-hidden="true">Boo!</b>
  <b aria-hidden="true">Boo!</b>
  <b aria-hidden="true">Boo!</b>
  <b aria-hidden="true">Boo!</b>
</button>
複製代碼

這樣就沒有重複的內容了。

就是這樣

經過額外元素及使用 CSS 咱們能夠實現具備方向感知性的幽靈按鈕。使用預處理器或將它們作爲一個組件放在應用裏,這樣咱們就不用每次都寫了。

  1. 這裏是一個經過方向感知填充文本效果的例子,實現方式與本文思路基本一致:Direction aware filling text effect
  2. 這篇文章裏彙總了好些鼠標懸停判斷方向的例子,有純 CSS 實現的,也有經過 JS 實現的。Direction Aware Hover Effects

譯者:Mark Wong

原文:css-tricks.com/ghost-butto…

相關文章
相關標籤/搜索