切換開關與開關設計系統
目的
切換開關與開關設計系統提供了一個標準化框架,用於在網頁介面中設計、定位和實作二元狀態控制項。切換開關模擬實體開關,可立即觸發或切換狀態變更、設定偏好或功能狀態,無需手動提交表單(例如點擊「儲存」)。
如果沒有專用的開關設計系統,介面常會誤用切換開關替代核取方塊、在停用或非活躍狀態下無法滿足 WCAG 對比度要求、缺乏明確的狀態標籤、觸控目標過小不適合行動裝置螢幕,或在不提供即時視覺反饋的情況下觸發意外的版面位移和背景副作用。
本系統制定了開關的幾何形狀、軌道與滑塊比例、標籤對齊方式、狀態顏色對映、鍵盤無障礙 (role="switch")、觸控點擊區域擴展、響應式列表佈局以及非同步待處理/載入狀態等規則。
使用案例
- 應用程式設定與偏好設定: 切換即時系統偏好(例如「推播通知」、「深色主題」、「自動儲存草稿」或「雙重驗證」)。
- 訂閱與帳單週期選擇: 在月付與年付計費週期之間切換定價卡片層級,並附帶行內折扣標籤。
- 資料表格列控制: 直接在資料表格列中啟用或停用個別使用者權限、API 整合、Webhook 或自動化規則。
- 功能標誌與系統模式切換: 在開發人員儀表板中切換操作狀態(例如「維護模式」、「除錯記錄」或「Beta 功能」)。
- 隱私權與 Cookie 同意面板: 在滑出式抽屜或 modal 對話框中管理精細的追蹤權限(例如「分析 Cookie」、「行銷 Cookie」)。
何時不應使用
- 多選項選擇: 若需在 3 個或更多互斥選項中選擇,請使用
segmented-control-system或custom-select-and-combobox-system。 - 需要明確核准的表單提交: 對於標準多欄位表單中需要點擊「提交」按鈕的同意條款(例如「我接受服務條款」),請使用標準核取方塊 (
form-design-system)。 - 非即時生效的二元選擇: 如果切換控制項不會立即生效,而需等到按下「套用」或「儲存變更」按鈕,請改用核取方塊而非開關。
- 表格中的批次選取: 若要選取多個項目進行批次操作(例如「刪除選取項目」),請使用核取方塊 (
data-table-ui-system)。
輸入
- 狀態定義: 二元狀態參數(關閉/未選取/
false與 開啟/已選取/true)。 - 情境與執行模式: 即時用戶端狀態變更(例如深色主題切換)與非同步伺服器副作用(例如 API Webhook 啟用/停用)。
- 標籤結構: 行內標籤文字、輔助說明/幫助文字以及狀態徽章需求。
- 佈局情境: 獨立設定卡片、密集表格列、多項目偏好群組或主打定價切換。
- 主題與設計代幣調色盤: 表面顏色、活躍軌道顏色、非活躍軌道顏色、滑塊顏色以及焦點環偏移代幣。
輸出
- 開關幾何與代幣規格: 軌道寬度、高度、滑塊直徑、圓角半徑和轉場時間的空間尺寸(
width: 44px、height: 24px、thumb: 20px)。 - 狀態與對比度藍圖: 調色盤代幣,確保在預設(關閉)、活躍(開啟)、懸停、焦點可見、停用和待處理狀態下,軌道與滑塊的最低 WCAG 3:1 圖形物件對比度。
- 結構佈局與字體排印規格: 開關元素、主要標籤 (
h4/span)、說明文字和可選狀態指示器 (ON/OFF) 之間的間距關係。 - 無障礙與 ARIA 對應: 語意化 HTML
<button role="switch" aria-checked="true|false">結構,並透過aria-labelledby/aria-describedby關聯螢幕閱讀器標籤。 - 非同步處理協議: 針對背景網路驗證的視覺載入狀態規範(滑塊內旋轉圖示或降低軌道不透明度)。
工作流程
1. 確定控制項語意(開關 vs 核取方塊)
在進行視覺設計之前,請確認互動意圖符合實體開關的心理模型:
- 即時效果: 切換開關會立即生效(或觸發即時的背景請求)。
- 獨立動作: 無需明確的「儲存」或「提交」確認按鈕即可獨立運作。
- 開啟/關閉狀態隱喻: 代表將功能或狀態開啟或關閉,而非在多欄位問卷中進行選取。
2. 建立空間幾何與觸控邊距
設計開關元件時,其比例應符合行動觸控指南,同時在桌機上維持視覺和諧:
[ 非活躍 / 關閉軌道 ] [ 活躍 / 開啟軌道 ]
+--------------------------+ +-------------------------+
| (滑塊) | -----> | (滑塊) |
| 20px | | 20px |
+--------------------------+ +-------------------------+
<-------- 44px ------------> <-------- 44px ----------->
24px 高度 24px 高度
- 標準開關比例:
- 軌道寬度:
44px(或2.75rem) - 軌道高度:
24px(或1.5rem) - 軌道邊框圓角:
999px(完整藥丸形狀) - 滑塊直徑:
20px(所有邊緣保留2px內軌道內縮量) - 滑塊邊框圓角:
50%(圓形)
- 軌道寬度:
- 緊湊/密集開關比例(表格列):
- 軌道寬度:
36px - 軌道高度:
20px - 滑塊直徑:
16px(含2px內縮量)
- 軌道寬度:
- 觸控目標外圍區域:
- 在行動裝置上,互動點擊區域必須使用偽元素 (
::before/::after) 或內距擴充至至少 44x44px,以防止觸控螢幕上的誤點擊。
- 在行動裝置上,互動點擊區域必須使用偽元素 (
3. 定義狀態顏色代幣與對比度指標
為滿足 WCAG 2.1 / 2.2 AA 非文字對比度要求(SC 1.4.11 - 最低 3:1),請遵循嚴格的顏色代幣配對:
- 非活躍 / 關閉狀態:
- 軌道背景:中性灰色表面(
#E2E8F0/ 深色模式:#334155)。 - 軌道邊框:1px 邊框(
#CBD5E1/ 深色模式:#475569),以確保與淺色背景表面達到 3:1 對比度。 - 滑塊顏色:純白或淺色表面(
#FFFFFF/ 深色模式:#F8FAFC)。 - 滑塊內可選圖示:月亮/太陽或叉號/勾選圖示 (
12px),提供雙重視覺反饋。
- 軌道背景:中性灰色表面(
- 活躍 / 開啟狀態:
- 軌道背景:高對比度品牌或系統動作顏色(
#2563EB主要藍色或#16A34A成功綠色)。與背景頁面表面的對比度必須超過 3:1。 - 軌道邊框:透明或與活躍邊框相符。
- 滑塊顏色:純白(
#FFFFFF),搭配平滑 CSS 轉場(transform: translateX(20px),時長200ms cubic-bezier(0.4, 0, 0.2, 1))。
- 軌道背景:高對比度品牌或系統動作顏色(
- 懸停與焦點狀態:
- 懸停:微妙的軌道亮度變化(+5% 或 -5%)或滑塊陰影放大(
box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.15))。 - 焦點可見:明顯的 2px 偏移焦點環(
outline: 2px solid #2563EB; outline-offset: 2px)。
- 懸停:微妙的軌道亮度變化(+5% 或 -5%)或滑塊陰影放大(
- 停用狀態:
- 軌道與滑塊不透明度:降至
0.5或0.4,並設定cursor: not-allowed。
- 軌道與滑塊不透明度:降至
4. 佈局標籤對齊與說明層級
開關應始終附帶清晰的文字標籤。切勿在沒有無障礙標籤或可見上下文的情況下呈現孤立的開關。
- 水平列佈局(預設偏好卡片):
- 將文字區塊置於左側(標題 + 說明),並將開關置於右側邊緣。
- 對齊開關軌道的垂直中心與標題文字的第一行(而非在多行說明的中央)。
- 標題文字與開關元素之間保持至少
16px的間距。
- 表單行內佈局:
- 將開關置於左側,標籤文字置於右側(
gap: 12px),建議在開關整合於密集表單欄位中時使用。
- 將開關置於左側,標籤文字置於右側(
- 定價層級切換佈局:
- 將開關水平置於兩個明確的標籤選項之間(例如「月付」— [ 開關 ] —「年付 (省 20%)」)。點擊任一文字標籤或開關即可切換活躍狀態。
5. 處理非同步副作用與載入狀態
當開關觸發非同步 API 呼叫(例如變更雲端資源設定或啟用整合)時:
- 樂觀視覺狀態: 立即將滑塊滑至目標位置(
aria-checked="true")。 - 待處理反饋: 在滑塊內部呈現微妙的旋轉圖示覆蓋層,或在網路延遲期間略微降低軌道不透明度。
- 錯誤復原: 若伺服器回傳錯誤,請顯示行內 toast/警示訊息,並將滑塊平滑動畫回先前的狀態,同時設定
aria-checked="false"。
6. 實作 WCAG AA 無障礙模式
確保所有瀏覽器引擎均支援原生鍵盤導航和螢幕閱讀器:
- 語意化 HTML 標記:
<button type="button" role="switch" aria-checked="true" id="push-notifications-switch" aria-labelledby="push-notifications-label" aria-describedby="push-notifications-desc" class="toggle-switch"> <span class="toggle-switch__track"> <span class="toggle-switch__thumb"></span> </span> </button> - 鍵盤互動:
- 可透過
Tab鍵導航取得焦點。 - 按下
Space或Enter可切換aria-checked狀態(true<->false),並觸發相關處理器。
- 可透過
- 螢幕閱讀器宣告:
- 螢幕閱讀器會明確宣告:「推播通知,開關,開啟」或「推播通知,開關,關閉」。
- 若標籤中已有開關的原生 ARIA 狀態,請勿再撰寫「開啟/關閉」等文字,以免造成資訊重複。
決策規則
開關 vs. 核取方塊 vs. 分段控制項選擇矩陣
| 情境 / 需求 | 建議控制項 | 理由 |
|---|---|---|
| 單一二元選擇,且即時生效(例如深色主題) | 切換開關 | 即時執行模型符合實體開關的特性。 |
| 已提交表單內的單一二元選擇(例如接受條款) | 核取方塊 | 變更需等到點擊「提交」按鈕後才會生效。 |
| 從清單中選取多個項目(例如選取 5 封電子郵件) | 核取方塊 | 標準的批次選取行為。 |
| 在 2 種不同模式之間選擇(例如網格檢視 vs. 列表檢視) | 分段控制項 | 兩種狀態標籤會並排保持可見。 |
| 在行動列表檢視中設定選項的開啟/關閉 | 切換開關 | 清晰的滑塊目標與明確的狀態反饋。 |
標籤位置矩陣
| 佈局情境 | 開關位置 | 標籤位置 | 空間行為 |
|---|---|---|---|
| 設定偏好列表 | 靠右對齊 | 靠左對齊 | justify-content: space-between 橫跨列容器。 |
| 行內表單欄位 | 靠左對齊 | 靠右對齊 | display: inline-flex; align-items: center; gap: 12px。 |
| 主打定價切換 | 居中錨定 | 左右兩側 | 左右兩側分別為「月付」和「年付」文字選項。 |
限制條件
- 無障礙(WCAG 2.1 / 2.2 AA):
- 在開啟和關閉狀態下,軌道邊框/背景與滑塊相對於頁面背景的非文字對比度最低需達到 3:1。
- 所有相關標籤和說明輔助文字的文字對比度最低需達到 4.5:1。
- 焦點環與周圍背景的對比度至少需達到 3:1,且厚度至少需為 2px。
- 觸控目標:
- 在觸控裝置上,互動觸控區域必須至少達到 44x44px(WCAG 2.5.5 / 2.5.8)。
- 顏色獨立性:
- 顏色不得作為狀態的唯一指示。滑塊的實際空間位置(左側 = 關閉,右側 = 開啟)以及語意化的
aria-checked值必須獨立於顏色來傳達狀態。
- 顏色不得作為狀態的唯一指示。滑塊的實際空間位置(左側 = 關閉,右側 = 開啟)以及語意化的
常見失敗模式
- 在提交表單中誤用開關: 在表單中使用開關,但變更需等到按下獨立的「儲存」按鈕才會生效,讓使用者困惑為何沒有即時套用。
- 軌道對比度不足: 使用淺灰色軌道(
#F1F5F9)搭配白色背景,且沒有邊界邊框,導致低視力使用者無法看見開關。 - 僅用顏色溝通狀態: 完全依賴紅色與綠色的軌道顏色,而未移動滑塊位置或更新 ARIA 屬性。
- 微小的觸控目標: 將點擊區域限制在 36x20px 的視覺軌道內,導致在行動裝置上觸控感到挫折並經常錯過點擊。
- 缺少無障礙標籤: 呈現獨立的圖示開關,但沒有
aria-label或aria-labelledby參考。 - 多行文字重疊: 將開關垂直置中對齊於長達 4 行的說明明段落,破壞了與主要標題的視覺對齊。
驗證標準
- 開關使用語意化 HTML
<button role="switch" aria-checked="true|false">結構。 - 在開啟和關閉狀態下,軌道與滑塊相對於背景的對比度最低需達到 3:1。
- 鍵盤導航(
Tab、Space、Enter)可順暢切換開關狀態並更新aria-checked。 - 觸控點擊區域已使用不可見內距或偽元素擴展至至少 44x44px。
- 開關搭配可見、高對比度的標籤文字,並透過
aria-labelledby關聯。 - 開關位置在 150ms–250ms 內順暢轉場(
transform: translateX()),並符合prefers-reduced-motion規範。 - 響應式設定列表在狹窄的行動螢幕上維持適當的間距(
gap: 16px),且文字不會重疊。