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

概略說明如何建構可自動調整顏色、反應且無障礙的懸浮動作按鈕 (FAB) 元件。

在這篇文章中,我想分享如何建構可自適應顏色、回應式且無障礙的 FAB 元件。試用示範查看來源

如果你偏好觀看影片,請參閱這篇文章的 YouTube 版本:

總覽

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) 隨時能保存在可視區域中,方便您使用。這是位置 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 文件,焦點通常會移至頂部元素。反轉視覺順序可讓視障使用者和鍵盤使用者享有一致的體驗,因為主要動作的樣式比迷你按鈕大,可向視障使用者指出這是主要動作,而鍵盤使用者則會將其視為來源中的第一個項目。

開發人員工具會顯示兩個 Fab 按鈕,並疊加其格狀版面配置。以條紋模式顯示兩者之間的差距,並顯示經過計算的高度和寬度。

.fabs {
  

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

系統會使用 place-items 處理居中效果,而 gap 會在容器中放置的任何 FAB 按鈕之間增加間距。

FAB 按鈕

是時候為某些按鈕設定樣式,這些按鈕看起來會懸浮在所有元素上方。

預設 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 樣式

首先,讓按鈕變成有強烈陰影的邊框間距圓形按鈕,這是按鈕的第一個定義功能:

.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 按鈕建立變化版本。我們將部分 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) 容器後,我們新增了 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 回饋,讓他們知道互動已收到。

接著,請稍微調整 translateY,為 :active 狀態增添一點風格,讓按鈕產生不錯的按下效果:

.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);
    }
  }
}

結論

既然你知道我如何做到,你會怎麼做呢? 🙂

讓我們多方嘗試,瞭解在網路上建構應用程式的所有方式。

請製作示範作品,並在推特上傳連結,我會將其加入下方的社群重混曲目錄!

社群重混作品

尚無任何內容

資源