符合品牌形象的表單

網頁功能: accent-color

以往要自訂核取方塊和圓形按鈕等標準 HTML 表單元素並不容易。開發人員通常必須選擇使用瀏覽器預設值,或從頭建構自訂元件。建構自訂控制項相當耗時,而且容易導致無障礙問題或遺漏狀態 (例如核取方塊的不確定狀態)。

CSS 屬性 accent-color 可讓你輕鬆透過一行 CSS,將品牌顏色套用至內建 HTML 表單輸入內容,同時兼顧無障礙功能或內建瀏覽器功能。

導入方式

如要將品牌顏色套用至表單控制項,請按照下列步驟操作:

  1. 找出品牌顏色:選擇代表品牌的顏色。
  2. 套用 accent-color 屬性:在 CSS 中,將 accent-color 新增至元素或容器元素 (例如 body 或特定表單)。
  3. 支援深色模式 (選用,但建議採用):使用 color-scheme 讓瀏覽器知道網站支援深色模式,並視需要調整 accent-color,提高對比度。

程式碼範例:與品牌風格一致的表單控制項

:root {
  --brand-color: #6200ee;
}

/* Apply accent-color to the body or a specific container */
body {
  accent-color: var(--brand-color);
}

/* Optional: Adjust for dark mode if needed */
@media (prefers-color-scheme: dark) {
  :root {
    --brand-color: #bb86fc; /* A lighter shade for dark mode */
  }
}
<form>
  <!-- Checkbox -->
  <label for="subscribe">
    <input type="checkbox" id="subscribe" checked>
    Subscribe to newsletter
  </label>

  <!-- Radio Buttons -->
  <label for="plan-monthly">
    <input type="radio" id="plan-monthly" name="plan" value="monthly">
    Monthly
  </label>
  <label for="plan-yearly">
    <input type="radio" id="plan-yearly" name="plan" value="yearly" checked>
    Yearly
  </label>

  <!-- Range Slider -->
  <label for="volume">Volume:</label>
  <input type="range" id="volume" min="0" max="100" value="70">

  <!-- Progress Bar -->
  <label for="file">Upload Progress:</label>
  <progress id="file" max="100" value="70">70%</progress>
</form>

策略執行與最佳做法

  • 建議使用 accent-color 輕鬆設定表單控制項主題,以符合品牌形象。
  • 請勿盲目信任瀏覽器處理對比度的能力。雖然瀏覽器應會自動判斷合適的對比色,但 Safari (WebKit 錯誤 244233) 和 Android Chrome (Chromium 錯誤 343503163) 等實作項目中的已知錯誤,可能會導致勾號顏色無法反轉。如果使用的顏色與背景對比度不足 (例如在淺色模式下使用淺色,或在深色模式下使用深色),控制項可能會隱藏或難以辨識。
  • 務必結合 accent-color 和 color-scheme: light dark,確保表單控制項在淺色和深色主題中都能正常顯示。
  • 請勿使用與背景顏色過於接近的顏色,雖然瀏覽器會盡量確保對比度,但最好還是提供基本對比度良好的顏色。
  • 請勿假設 accent-color 適用於所有表單元素。目前只會為 checkbox、radio、range 和 progress 元素著色。

備用策略

如果瀏覽器不支援 accent-color,表單控制項會改用瀏覽器的預設外觀。為確保所有環境中的品牌一致性和高可靠性,您「必須」使用既有的「視覺隱藏輸入」技術,導入自訂備用策略。

使用 @supports not 進行漸進增強

您必須使用 @supports not 規則,在不支援 accent-color 時套用自訂備用樣式。這樣一來,您就能在新式瀏覽器上運用 accent-color 的簡便性,同時確保舊版瀏覽器也能提供一致的品牌體驗。

1. HTML 結構

請確保標籤將文字包在 <span> 中,以便在 CSS 中使用同層選取器:

<label for="subscribe-fallback">
  <input type="checkbox" id="subscribe-fallback" class="visually-hidden" checked>
  <span>Subscribe to newsletter</span>
</label>

2. CSS 備用廣告

在 @supports not 區塊中套用自訂樣式:

/* Fallback for older browsers without accent-color */
@supports not (accent-color: var(--brand-color)) {
  /* Visually hide the native input using the canonical accessible recipe */
  form input[type="checkbox"].visually-hidden {
    position: absolute !important;
    clip-path: inset(50%) !important;
    overflow: hidden !important;
    width: 1px !important;
    height: 1px !important;
    margin: -1px !important;
    padding: 0 !important;
    border: 0 !important;
    white-space: nowrap !important;
  }

  /* Style the wrapper label */
  label {
    position: relative;
    padding-left: 2rem;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
  }

  /* Custom box for checkbox */
  input[type="checkbox"] + span::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 1.2rem;
    height: 1.2rem;
    border: 2px solid #ccc;
    background: white;
    border-radius: 4px;
    box-sizing: border-box;
    transition: all 0.2s ease;
  }

  /* Ensure custom checkbox shows focus for keyboard users */
  input[type="checkbox"]:focus-visible + span::before {
    outline: 2px solid #000;
    outline-offset: 2px;
  }

  /* Checked State */
  input[type="checkbox"]:checked + span::before {
    background-color: var(--brand-color, #6200ee);
    border-color: var(--brand-color, #6200ee);
  }

  /* Checkmark (Unicode) */
  input[type="checkbox"]:checked + span::after {
    content: "✓";
    position: absolute;
    left: 0.25rem;
    top: 50%;
    transform: translateY(-50%);
    color: white;
    font-weight: bold;
    font-size: 0.9rem;
  }

  /* Fallback for Range Slider */
  input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    background: transparent;
  }

  /* Webkit (Chrome, Safari, Edge) */
  input[type="range"]::-webkit-slider-runnable-track {
    width: 100%;
    height: 8px;
    /* Use gradient to show progress for a static value (e.g., 70%) or update with JS */
    background: linear-gradient(to right, var(--brand-color, #6200ee) 70%, #ccc 70%);
    border-radius: 4px;
  }

  input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    height: 16px;
    width: 16px;
    border-radius: 50%;
    background: var(--brand-color, #6200ee);
    cursor: pointer;
    margin-top: -4px; /* Center vertically */
  }

  /* Firefox */
  input[type="range"]::-moz-range-track {
    width: 100%;
    height: 8px;
    background: #ccc;
    border-radius: 4px;
  }

  input[type="range"]::-moz-range-thumb {
    height: 16px;
    width: 16px;
    border-radius: 50%;
    background: var(--brand-color, #6200ee);
    cursor: pointer;
  }

  /* Firefox specific progress bar */
  input[type="range"]::-moz-range-progress {
    background-color: var(--brand-color, #6200ee);
    height: 8px;
    border-radius: 4px;
  }

  /* Fallback for Progress Bar */
  progress {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    border: none;
    background: #ccc;
    height: 8px;
    border-radius: 4px;
  }

  progress::-webkit-progress-bar {
    background-color: #ccc;
    border-radius: 4px;
  }

  progress::-webkit-progress-value {
    background-color: var(--brand-color, #6200ee);
    border-radius: 4px;
  }

  progress::-moz-progress-bar {
    background-color: var(--brand-color, #6200ee);
    border-radius: 4px;
  }
}

Webkit 備用廣告中的動態範圍進度

如要在 Webkit 瀏覽器中 (不含 accent-color),讓進度填滿效果隨著範圍滑桿上的滑桿移動,可以使用 CSS 變數和少量 JavaScript。

  1. 更新 CSS:使用 CSS 變數設定漸層色標:

    input[type="range"]::-webkit-slider-runnable-track {
      background: linear-gradient(to right, var(--brand-color) var(--progress, 0%), #ccc var(--progress, 0%));
    }
    
  2. 新增 JavaScript:更新 input 事件的變數:

if (!CSS.supports('accent-color')) {
  const slider = document.getElementById('volume');
  slider.addEventListener('input', (e) => {
    e.target.style.setProperty('--progress', `${e.target.value}%`);
  });
}