スタイル設定された進行状況バーを作成する

<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 で UA の境界をリセットする
  • アクティブ バーを要素の border-radius にクリップするには、overflow: clip を使用するか、同じ border-radius をバーに適用します。バーで border-radius: inherit を使用しないでください。これは、シャドウ 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() は疑似要素をサポートしていないため、ここでは役に立ちません。
  • ブラウザをターゲットとする各疑似要素は、1 回だけ出現する必要があります。状態固有のカスタマイズ(不確定なセグメント サイズやアニメーションなど)は、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 を使用します。margin-right: auto を from, to に含めると、Chromium は RTL でも物理的な左側に塗りつぶしを配置します。
  • 塗りつぶしを移動するには、マージンではなく変換を使用します。
    • 変換では、アニメーションがコンポジタに保持されます(inline-size もアニメーション化されている場合を除く)。
    • RTL でマージンが崩れる理由は 2 つあります。
    • 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 を 2 つの同時アニメーションに設定します。1 つはキーフレームが cqi(位置)で translate をアニメーション化するアニメーション、もう 1 つはキーフレームが inline-size(長さ)をアニメーション化するアニメーションです。これにより、それぞれに独自のキーフレームとイージングが設定されます。1 つのキーフレーム リストで両方のエッジをシェーピングしようとしないでください。キーフレームごとの 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 を設定したり、<progress> で .focus() を呼び出したりしないでください。バックグラウンド タスクが完了したときに読み上げるには、polite ステータス要素(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 プロパティはプログレッシブ エンハンスメントです。このプロパティをサポートしていないブラウザでは、このプロパティは無視され、デフォルトの UI カラーが使用されます。

accent-color がサポートされておらず、進行状況バーのスタイル設定が必要な場合は、カスタマイズされたスタイル設定方法を使用して、進行状況バーに好みのスタイルを適用します。

revert-rule のフォールバックとブラウザ サポート

revert-rule がサポートされていない場合、--progress-bar-animation が設定されていないと、animation: var(--progress-bar-animation, revert-rule) は 0s の期間で animation-name: revert-rule にフォールバックします。これは、@keyframes revert-rule が存在しない場合は無害な no-op です。