建構懸浮動作按鈕 (FAB) 元件

基礎概念簡介:如何建構可適應顏色、回應式且無障礙的 FAB 元件。

在這篇文章中,我想分享我對如何建構可自動調整顏色、具備回應性且符合無障礙設計的 FAB 元件的想法。試用示範查看來源

如果比較喜歡看影片,可以觀看這篇貼文的 YouTube 版本:

總覽

FAB 在行動裝置上比在電腦上更常見,但這兩種情境都普遍使用 FAB。這些按鈕會顯示主要動作,方便使用者隨時執行。這種使用者體驗風格因 Material UI 而聲名大噪,如需使用和放置建議,請參閱這篇文章

元素和樣式

這些控制項的 HTML 包含容器元素和一組一或多個按鈕。容器會在可視區域內放置 FAB,並管理按鈕之間的間距。按鈕可以是迷你或預設大小,讓主要和次要動作之間有更多變化。

懸浮動作按鈕容器

這個元素可以是普通的 <div>,但為了照顧視障使用者,我們不妨加上一些實用屬性,說明這個容器的用途和內容。

FAB 標記

先使用 .fabs 類別,以便 CSS 連結樣式,然後新增 role="group"aria-label,這樣就不只是通用容器,而是有名稱且有用途。

<div class="fabs" role="group" aria-label="Floating action buttons">
  <!-- buttons will go here -->
</div>

懸浮動作按鈕樣式

為了方便使用,FAB 會隨時固定在可視區域內。 這是位置 <0x0A>fixed 的絕佳用途。在這個檢視區塊位置中,我選擇使用 inset-blockinset-inline,因此位置會與使用者的文件模式相輔相成,例如從右到左或從左到右。自訂屬性也可用於避免重複,並確保與檢視區塊底部和側邊緣的距離相等:

.fabs {
  --_viewport-margin: 2.5vmin;

  position: fixed;
  z-index: var(--layer-1);

  inset-block: auto var(--_viewport-margin);
  inset-inline: auto var(--_viewport-margin);
}

接著,我提供容器顯示 flex,並將版面配置方向變更為 column-reverse。這會將子項彼此堆疊 (直欄),並反轉視覺順序。這會使第一個可聚焦的元素成為底部元素,而非頂端元素,而根據 HTML 文件,焦點通常會移至頂端元素。反轉視覺順序可統一有視力使用者和鍵盤使用者的體驗,因為主要動作的樣式比迷你按鈕大,有視力使用者會知道這是主要動作,而鍵盤使用者會將其做為來源中的第一個項目。

畫面顯示兩個快速動作按鈕,開發人員工具則疊加在按鈕的格線版面配置上。以條紋圖案顯示兩者之間的間隙,並顯示計算出的高度和寬度。

.fabs {
  

  display: flex;
  flex-direction: column-reverse;
  place-items: center;
  gap: var(--_viewport-margin);
}

置中作業由 place-items 處理,而 gap 則會在容器中放置的任何 FAB 按鈕之間新增空格。

懸浮動作按鈕

現在要為按鈕設定樣式,讓按鈕看起來像是浮在所有項目上方。

預設 FAB

要設定樣式的第一個按鈕是預設按鈕。所有 FAB 按鈕都會以此為基礎。稍後我們會建立變化版本,盡可能減少修改這些基本樣式,同時達成替代外觀。

懸浮動作按鈕標記

<button> 元素是正確的選擇。我們將以此為基礎,因為這項功能提供優異的滑鼠、觸控和鍵盤使用者體驗。這項標記最重要的部分,是使用 aria-hidden="true" 對螢幕閱讀器使用者隱藏圖示,並在 <button> 標記本身加入必要的標籤文字。在這些情況下新增標籤時,我也喜歡加入 title,這樣滑鼠使用者就能取得圖示希望傳達的資訊。

<button data-icon="plus" class="fab" title="Add new action" aria-label="Add new action">
  <svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>

懸浮動作按鈕樣式

首先,請將按鈕變成具有強烈陰影的圓形按鈕,因為這些是按鈕的第一個定義特徵:

.fab {
  --_size: 2rem;

  padding: calc(var(--_size) / 2);
  border-radius: var(--radius-round);
  aspect-ratio: 1;
  box-shadow: var(--shadow-4);
}

接著加入顏色。我們會採用先前在 GUI 挑戰中使用的策略。 建立一組名稱清楚的自訂屬性,靜態保留淺色和深色,然後建立一個適應性自訂屬性,根據使用者對色彩的系統偏好設定,將其設為淺色或深色變數:

.fab {
  

  /* light button and button hover */
  --_light-bg: var(--pink-6);
  --_light-bg-hover: var(--pink-7);

  /* dark button and button hover */
  --_dark-bg: var(--pink-4);
  --_dark-bg-hover: var(--pink-3);

  /* adaptive variables set to light by default */
  --_bg: var(--_light-bg);

  /* static icon colors set to the adaptive foreground variable */
  --_light-fg: white;
  --_dark-fg: black;
  --_fg: var(--_light-fg);

  /* use the adaptive properties on some styles */
  background: var(--_bg);
  color: var(--_fg);

  &:is(:active, :hover, :focus-visible) {
    --_bg: var(--_light-bg-hover);

    @media (prefers-color-scheme: dark) {
      --_bg: var(--_dark-bg-hover);
    }
  }

  /* if users prefers dark, set adaptive props to dark */
  @media (prefers-color-scheme: dark) {
    --_bg: var(--_dark-bg);
    --_fg: var(--_dark-fg);
  }
}

接著新增一些樣式,讓 SVG 圖示符合空間。

.fab {
  

  & > svg {
    inline-size: var(--_size);
    block-size: var(--_size);
    stroke-width: 3px;
  }
}

最後,移除按鈕的輕觸醒目顯示效果,因為我們已為互動新增自己的視覺回饋:

.fab {
  -webkit-tap-highlight-color: transparent;
}

迷你懸浮動作按鈕

本節的目標是為 FAB 按鈕建立變體。將部分 FAB 縮小,小於預設動作,即可宣傳使用者最常執行的動作。

迷你懸浮動作按鈕標記

HTML 與 FAB 相同,但我們新增了「.mini」類別,為 CSS 提供變體的掛鉤。

<button data-icon="heart" class="fab mini" title="Like action" aria-label="Like action">
  <svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>
迷你懸浮動作按鈕樣式

由於使用了自訂屬性,因此只需要調整 --_size 變數。

.fab.mini {
  --_size: 1.25rem;
}

螢幕截圖:兩個 FAB 按鈕堆疊在一起,頂端按鈕比底部按鈕小。

無障礙設定

使用 FAB 時,無障礙功能最重要的部分是頁面鍵盤流程中的位置。這個示範只有 FAB,在鍵盤順序和流程方面沒有任何競爭,因此無法展示有意義的鍵盤流程。如果有多個元素爭奪焦點,建議您深入思考使用者應在流程中的哪個位置進入 FAB 按鈕流程。

Keyboard interaction demonstration

使用者將焦點移至 FAB 容器後,我們已新增 role="group"aria-label="floating action buttons",可向螢幕閱讀器使用者說明焦點所在位置的內容。我已策略性地將預設 FAB 放在最前面,讓使用者優先看到主要動作。然後使用 flex-direction: column-reverse;,將主要按鈕放在底部,靠近使用者手指,方便存取。這項做法相當成功,因為預設按鈕在視覺上很顯眼,且鍵盤使用者會優先看到這個按鈕,因此能獲得非常相似的體驗。

最後,別忘了對螢幕閱讀器使用者隱藏圖示,並為按鈕提供標籤,確保使用者不會感到困惑。這項作業已在 HTML 中完成,方法是在 <svg> 上使用 aria-hidden="true",並在 <button> 上使用 aria-label="Some action"

動畫

您可以加入各種動畫,提升使用者體驗。如同其他 GUI 挑戰,我們會設定幾個自訂屬性,分別保留減少動作體驗和完整動作體驗的意圖。根據預設,樣式會假設使用者想要減少動作,然後使用 prefers-reduced-motion 媒體查詢將轉換值換成完整動作。

使用自訂屬性的減少動態效果策略

下列 CSS 中建立了三個自訂屬性:--_motion-reduced--_motion-ok--_transition。前兩個變數會根據使用者的偏好設定保留適當的轉場效果,最後一個變數 --_transition 則會分別設為 --_motion-reduced--_motion-ok

.fab {
  /* box-shadow and background-color can safely be transitioned for reduced motion users */
  --_motion-reduced:
    box-shadow .2s var(--ease-3),
    background-color .3s var(--ease-3);

  /* add transform and outline-offset for users ok with motion */
  --_motion-ok:
    var(--_motion-reduced),
    transform .2s var(--ease-3),
    outline-offset 145ms var(--ease-2);

  /* default the transition styles to reduced motion */
  --_transition: var(--_motion-reduced);

  /* set the transition to our adaptive transition custom property*/
  transition: var(--_transition);

  /* if motion is ok, update the adaptive prop to the respective transition prop */
  @media (prefers-reduced-motion: no-preference) {
    --_transition: var(--_motion-ok);
  }
}

完成上述設定後,box-shadowbackground-colortransformoutline-offset 的變更即可轉換,讓使用者獲得良好的 UI 回饋,得知系統已收到互動。

接著,調整 :active 狀態,為按鈕增添一點風格,讓按鈕呈現按壓效果: translateY

.fab {
  

  &:active {
    @media (prefers-reduced-motion: no-preference) {
      transform: translateY(2%);
    }
  }
}

最後,將按鈕中 SVG 圖示的任何變更轉換為:

.fab {
  

  &[data-icon="plus"]:hover > svg {
    transform: rotateZ(.25turn);
  }

  & > svg {
    @media (prefers-reduced-motion: no-preference) {
      will-change: transform;
      transition: transform .5s var(--ease-squish-3);
    }
  }
}

結論

現在您已瞭解我的做法,您會怎麼做呢?🙂

讓我們多元化地運用各種方法,學習在網路上建構內容。

建立試聽版,然後在推特上傳送連結給我,我會將連結加到下方的社群混音區!

社群重混作品

目前沒有任何內容。

資源