基礎概念簡介:如何建構可適應顏色、回應式且無障礙的 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-block 和 inset-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 容器後,我們已新增 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-shadow、background-color、transform 和 outline-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);
}
}
}
結論
現在您已瞭解我的做法,您會怎麼做呢?🙂
讓我們多元化地運用各種方法,學習在網路上建構內容。
建立試聽版,然後在推特上傳送連結給我,我會將連結加到下方的社群混音區!
社群重混作品
目前沒有任何內容。
資源
- Github 上的原始碼