建立樣式進度列

<progress> 元素是表示工作完成進度的語意方式,例如下載或上傳資訊,或完成多步驟程序的一部分。使用原生元素有助於提升無障礙程度,因為螢幕閱讀器具有隱含的 role="progressbar",可以讀出值。

本指南會實作完全自訂樣式的水平進度列。

進度列或進度環?

  • 如果空間有限或偏好正方形顯示比例,建議使用圓形進度列 (進度環):進度環
  • 在大多數不確定進度的情況下,建議使用旋轉圖示 (載入旋轉圖示)。如果進度不確定狀態只是暫時性,且很快就會由確定進度列取代,請使用不確定進度列 (例如等待上傳相關中繼資料,才能顯示進度百分比)

標記

  1. 使用原生 <progress> 元素:提供內建無障礙功能和平台一致的行為。
  2. 如需使用預設 0-1 以外的評分系統,請使用 max。
  3. 如要設定特定進度值,請設定 value 屬性。如要表示不確定狀態 (例如在開始提供更具體的回饋之前),請省略 value。
  4. 使用 <label for="...">、aria-labelledby 或 aria-label,將進度元素與標籤建立關聯。

需要哪種自訂功能?

如要進行有限的樣式設定,下列屬性就足夠:

  • accent-color:變更進度列的顏色
  • width/inline-size:變更進度列寬度
  • height/block-size 套用方式不一致,請先測試
  • writing-mode: vertical-lr:垂直長條。
  • 繪製後套用的效果:opacity、filter、clip-path、遮罩、轉換、box-shadow 等。

如果有限的樣式設定已足夠,請略過下一節。

警告:某些屬性 (例如 border-radius、background、border) 會在不顯示任何訊息的情況下,停用預設進度列樣式。如果需要上述屬性以外的樣式,請按照下一節的說明,實作完全自訂的樣式。請勿套用更多樣式,以免「只是碰巧有效」。

完全自訂樣式

1. 基本設定

  • 必要:使用 appearance: none 啟用自訂樣式。
  • 使用 border: 0 solid 重設通用 Analytics 邊界
  • 如要將有效長條裁剪至元素的 border-radius,請使用 overflow: clip,或將相同的 border-radius 套用至長條。請勿在列上使用 border-radius: inherit,這取決於 Shadow DOM 中元素的特定結構。
progress {
  /* Reset default browser styles */
  appearance: none;
  border: 0 solid;
  /* Clip bar to element’s border-radius  */
  overflow: clip;
}

2. 樣式

  • 在 progress 元素本身設定軌道樣式。
  • 使用適當的瀏覽器指定虛擬元素,指定進度列本身:WebKit/Blink 使用 ::-webkit-progress-value,Firefox 使用 ::-moz-progress-bar。
  • 強制規定:請勿在同一規則中將 -webkit- 和 -moz- 虛擬元素分組。系統會將規則視為無效並忽略。:is() 和 :where() 不支援虛擬元素,因此無法解決這個問題。
  • 每個瀏覽器指定的虛擬元素只能出現一次。特定狀態的自訂項目 (例如不確定區隔大小和動畫) 應透過 progress 元素本身設定的自訂屬性進行轉送。
  • 選用:在填滿時轉換 inline-size,讓確定值變更時顯示動畫,而不是跳轉。Firefox 會調整版面配置中的填滿大小,並忽略該屬性,這不會造成任何影響。
progress {
  --progress-bar-radius: 1e5px;
  border-radius: var(--progress-bar-radius);
  /* Apply color for custom progress track (background) */
  background: var(--progress-bar-track, var(--color-neutral-90));
  /* Subtle depth on the empty part of the track */
  box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.1);
}

/* Let <progress> styling show through */
progress::-webkit-progress-bar {
  background: transparent;
}

/* Webkit, Chrome */
progress::-webkit-progress-value {
  background: var(--progress-bar-fill, var(--accent-color));
  border-radius: var(--progress-bar-radius);
  transition: inline-size 0.3s;
}

/* Firefox */
progress::-moz-progress-bar {
  background: var(--progress-bar-fill, var(--accent-color));
  border-radius: var(--progress-bar-radius);
  transition: inline-size 0.3s;
}

3. 不確定狀態樣式

為不確定狀態新增自訂動畫:將填滿虛擬元素轉換為短片段,並沿著軌道滑動。

  • 請設定填滿效果本身的樣式,不要在 progress 上重新建立為背景。
  • 不確定填滿效果只會透過動畫呈現:主要畫面格會使用實際的 inline-size 設定長度 (這會覆寫 Chromium 的 UA 內嵌 inline-size),並使用 translate 移動。請勿使用 scale 做為長度,否則會扭曲填滿區域上繪製的任何圖案。
  • translate 百分比會根據填滿寬度解析,因此請改用軌道單位表示位置:將 progress 設為內嵌大小容器,並在主要畫面格中使用 cqi。在 from, to 中加入 margin-right: auto,這樣 Chromium 在 RTL 模式下也會將填滿效果放在實際左側。
  • 請使用轉換 (而非邊界) 移動填滿。
    • 轉換會將動畫保留在合成器中 (除非 inline-size 也正在動畫中)
    • 邊界在 RTL 中會中斷,原因有兩個:
    • Firefox 只會使用實體左側邊界來定位不確定填滿,因此 margin-inline-start 在 RTL 中不會產生任何效果,且填滿永遠不會移動。
    • 在 Chromium 和 WebKit 中,填滿會以一般區塊的形式呈現,一旦邊界將填滿推到軌道末端,邊界就會加總超過軌道。標準 CSS 會在 RTL 中忽略 margin-left,因此區隔會跳到邊緣,而不是滑出邊緣。
    • translate 會在版面配置後套用,因此不會發生上述問題。
  • 如要鏡像翻轉 RTL 的動作 (就像 Chrome 的原生列一樣),請反轉 :dir(rtl) 下方的動畫:
progress:dir(rtl) {
  --progress-bar-indeterminate-animation: progress-bar-indeterminate var(--progress-bar-indeterminate-animation-duration) infinite linear reverse;
}
  • 在 progress 上定義公開 --progress-bar-indeterminate-* 屬性 (其名稱已將其範圍限定為狀態),讓消費者可以覆寫這些屬性,而不需要知道 :indeterminate。
  • 如要改變線段長度 (例如前緣向前移動,後緣跟上),請將 --progress-bar-indeterminate-animation 設為兩個並行動畫:一個動畫的主要畫面格在 cqi (位置) 中為 translate 加上動畫效果,另一個動畫的主要畫面格則為 inline-size (長度) 加上動畫效果,這樣每個動畫都有自己的主要畫面格和加/減速。請勿嘗試在單一主要畫面格清單中設定兩邊的形狀;每個主要畫面格的 animation-timing-function 會套用至該主要畫面格中的每個屬性。
  • --progress-bar-animation 適用於這兩種狀態,可用於確定閃爍等效果。revert-rule 僅用於在設定時覆寫,以盡可能提高可組合性。
  • 請勿停用不確定動畫 (animation: none 會在 Chromium 中留下零寬度的填滿)。如要減少動態效果,請放慢速度。
progress {
  /* Lets the fill position itself in track units (cqi) */
  container-type: inline-size;
  /* Segment length relative to the track */
  --progress-bar-indeterminate-size: 30%;
  --progress-bar-indeterminate-animation-duration: 1.5s;

  /* Respect prefers-reduced-motion */
  @media (prefers-reduced-motion: reduce) {
    --progress-bar-indeterminate-animation-duration: 10s;
  }
}

progress:indeterminate {
  --progress-bar-animation: var(
      --progress-bar-indeterminate-animation,
      progress-bar-indeterminate var(--progress-bar-indeterminate-animation-duration) infinite linear
    );
}

/* Add to the existing pseudo-element rules */
progress::-webkit-progress-value {
  animation: var(--progress-bar-animation, revert-rule);
}

progress::-moz-progress-bar {
  animation: var(--progress-bar-animation, revert-rule);
}

/* Physical: left to right regardless of direction (reverse under :dir(rtl) to mirror). */
@keyframes progress-bar-indeterminate {
  from, to {
    inline-size: var(--progress-bar-indeterminate-size);
    /* Pin to the physical left; Chromium would otherwise lay the fill out at the inline start */
    margin-right: auto;
  }
  from { translate: -100%; } /* Own width: fully outside the left edge */
  to { translate: 100cqi; }  /* Track width: fully outside the right edge */
}

其他無障礙功能注意事項

除了上述規範外,請注意下列事項:

  • 宣布完成,但不搶走焦點:請勿在 <progress> 上設定 tabindex 或呼叫 .focus(),因為這不是互動式元素,將焦點移至該元素會干擾鍵盤使用者。如要在背景工作完成時發出通知,請更新禮貌狀態元素 (role="status" 或 aria-live="polite")。
  • 請勿在 <progress> 內加入備用文字:新式瀏覽器會忽略 <progress> 內的文字,輔助技術也不會使用。
  • 避免在未標示的一般 <div> 上使用 aria-busy + aria-describedby。aria-busy 的螢幕閱讀器支援功能不一致,且輔助技術會忽略未命名 <div> 上的 aria-describedby,且沒有角色。如果載入時區域內容尚未準備就緒,請使用 hidden 或 aria-hidden="true" 隱藏。
  • 建議:新增自訂樣式時,請確保進度列和軌道之間有適當的對比。
  • 考慮使用其他方式表示不確定狀態:與其他內容並列顯示的不確定進度列動畫,可能會干擾部分使用者。

備用策略

accent-color 的備用方案和瀏覽器支援

accent-color 屬性是漸進增強。不支援這項屬性的瀏覽器會忽略該屬性,並使用預設的使用者介面顏色。

如果系統不支援 accent-color,且需要設定進度列樣式,請使用自訂樣式方法,將偏好的樣式套用至進度列。

revert-rule 的備用方案和瀏覽器支援

如果不支援 revert-rule,animation: var(--progress-bar-animation, revert-rule) 會在未設定 --progress-bar-animation 時,改用 animation-name: revert-rule,並採用 0s 持續時間,如果沒有 @keyframes revert-rule,則會是無害的無作業。