表示例
72%
アップロード
別名・英語表記
- プログレスリング
- 円形プログレスバー
- 進捗リング
- ドーナツ型の進捗
- 丸い進捗表示
- 円のプログレス
- Circular progress
実装例
<div class="x-progress-circle">
<div class="x-progress-circle__item">
<div class="x-progress-circle__ring" role="progressbar" aria-labelledby="x-progress-circle-l1" aria-valuemin="0" aria-valuemax="100" aria-valuenow="72">
<svg class="x-progress-circle__svg" viewBox="0 0 64 64" aria-hidden="true" focusable="false">
<circle class="x-progress-circle__track" cx="32" cy="32" r="27"></circle>
<circle class="x-progress-circle__bar" cx="32" cy="32" r="27" pathLength="100" stroke-dasharray="72 100"></circle>
</svg>
<span class="x-progress-circle__num">72%</span>
</div>
<span class="x-progress-circle__l" id="x-progress-circle-l1">アップロード</span>
</div>
<div class="x-progress-circle__item">
<!-- 終わりが読めないときは aria-valuenow を付けない(不確定) -->
<div class="x-progress-circle__ring" role="progressbar" aria-labelledby="x-progress-circle-l2">
<svg class="x-progress-circle__svg x-progress-circle__svg--spin" viewBox="0 0 64 64" aria-hidden="true" focusable="false">
<circle class="x-progress-circle__track" cx="32" cy="32" r="27"></circle>
<circle class="x-progress-circle__bar" cx="32" cy="32" r="27" pathLength="100" stroke-dasharray="25 100"></circle>
</svg>
</div>
<span class="x-progress-circle__l" id="x-progress-circle-l2">処理中</span>
</div>
</div>
/* 貼った先のリセットに頼らないよう、この部品の中だけ border-box にする */
.x-progress-circle,
.x-progress-circle *:not([class*="fa-"]),
.x-progress-circle *:not([class*="fa-"])::before,
.x-progress-circle *:not([class*="fa-"])::after {
box-sizing: border-box;
/* 貼った先の既定の書体に引きずられないようにする。書体が変わると
文字の幅と高さが変わり、枠のサイズまでずれる */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
}
.x-progress-circle {
display: flex;
gap: 28px;
width: 240px;
max-width: 100%;
}
.x-progress-circle__item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.x-progress-circle__ring {
position: relative;
width: 88px;
height: 88px;
}
.x-progress-circle__svg {
display: block;
width: 100%;
height: 100%;
/* 円の描き始めは右(3時)なので、上(12時)から始まるよう回す */
transform: rotate(-90deg);
}
.x-progress-circle__track,
.x-progress-circle__bar {
fill: none;
stroke-width: 7;
}
.x-progress-circle__track {
stroke: #cfd4dc;
}
.x-progress-circle__bar {
stroke: #1d4ed8;
stroke-linecap: round;
}
.x-progress-circle__num {
position: absolute;
inset: 0;
display: grid;
place-items: center;
color: #1b2028;
font-size: 18px;
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.x-progress-circle__l {
color: #4b5563;
font-size: 13px;
font-weight: 700;
}
.x-progress-circle__svg--spin {
animation: x-progress-circle-turn 1s linear infinite;
}
@keyframes x-progress-circle-turn {
from {
transform: rotate(-90deg);
}
to {
transform: rotate(270deg);
}
}
/* 動きを減らす設定では回さない。「処理中」の文字で状態を伝える */
@media (prefers-reduced-motion: reduce) {
.x-progress-circle__svg--spin {
animation: none;
}
}
AIへの指示文
「円形プログレス(Circular progress)」を実装してください。
## これは何か
輪っかが時計回りに伸びて、どこまで進んだかを示す部品。真ん中に「72%」のように数字が入る。終わりが読めないときは輪が回る。
## 使いどころ
- アップロードや同期の進み具合を、限られた場所(アイコンの上・カードの角など)に出したいとき
- ダッシュボードで、達成率を数字と一緒に目立たせたいとき
## 実装の要件
- SVG の circle を2枚重ねる(下地の輪と進んだ分の輪)。進んだ分は pathLength="100" と stroke-dasharray="<値> 100" で描く
- SVG を -90度回して、12時の位置から伸ばす
- 不確定は短い弧を CSS の animation で回す
- プログレスバーと役目は同じで、細かい違いは読み取りにくい。横幅がとれるなら、長さを比べやすいプログレスバーを選ぶ
- ローディングスピナーは「待っている」ことだけを伝える。円形プログレスは、数字が分かるなら何%かを必ず出す
- 輪の長さだけでは何%か読み取れない。中央に数字を置く
## アクセシビリティの要件
- role="progressbar" に aria-valuenow / aria-valuemin / aria-valuemax と名前(aria-labelledby など)を付ける。SVG は aria-hidden="true"
- 終わりが読めないときは aria-valuenow を付けない。これで不確定の進捗として伝わる
- 回る動きは prefers-reduced-motion で止め、「処理中」の文字で状態を伝える
- 輪の色と下地の境目を、非テキストのコントラスト(3:1)以上にする
## 参考にする実装
この形を出発点にして、プロジェクトの命名規則・色・余白に合わせて調整してください。
```html
<div class="x-progress-circle">
<div class="x-progress-circle__item">
<div class="x-progress-circle__ring" role="progressbar" aria-labelledby="x-progress-circle-l1" aria-valuemin="0" aria-valuemax="100" aria-valuenow="72">
<svg class="x-progress-circle__svg" viewBox="0 0 64 64" aria-hidden="true" focusable="false">
<circle class="x-progress-circle__track" cx="32" cy="32" r="27"></circle>
<circle class="x-progress-circle__bar" cx="32" cy="32" r="27" pathLength="100" stroke-dasharray="72 100"></circle>
</svg>
<span class="x-progress-circle__num">72%</span>
</div>
<span class="x-progress-circle__l" id="x-progress-circle-l1">アップロード</span>
</div>
<div class="x-progress-circle__item">
<!-- 終わりが読めないときは aria-valuenow を付けない(不確定) -->
<div class="x-progress-circle__ring" role="progressbar" aria-labelledby="x-progress-circle-l2">
<svg class="x-progress-circle__svg x-progress-circle__svg--spin" viewBox="0 0 64 64" aria-hidden="true" focusable="false">
<circle class="x-progress-circle__track" cx="32" cy="32" r="27"></circle>
<circle class="x-progress-circle__bar" cx="32" cy="32" r="27" pathLength="100" stroke-dasharray="25 100"></circle>
</svg>
</div>
<span class="x-progress-circle__l" id="x-progress-circle-l2">処理中</span>
</div>
</div>
```
```css
/* 貼った先のリセットに頼らないよう、この部品の中だけ border-box にする */
.x-progress-circle,
.x-progress-circle *:not([class*="fa-"]),
.x-progress-circle *:not([class*="fa-"])::before,
.x-progress-circle *:not([class*="fa-"])::after {
box-sizing: border-box;
/* 貼った先の既定の書体に引きずられないようにする。書体が変わると
文字の幅と高さが変わり、枠のサイズまでずれる */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
}
.x-progress-circle {
display: flex;
gap: 28px;
width: 240px;
max-width: 100%;
}
.x-progress-circle__item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.x-progress-circle__ring {
position: relative;
width: 88px;
height: 88px;
}
.x-progress-circle__svg {
display: block;
width: 100%;
height: 100%;
/* 円の描き始めは右(3時)なので、上(12時)から始まるよう回す */
transform: rotate(-90deg);
}
.x-progress-circle__track,
.x-progress-circle__bar {
fill: none;
stroke-width: 7;
}
.x-progress-circle__track {
stroke: #cfd4dc;
}
.x-progress-circle__bar {
stroke: #1d4ed8;
stroke-linecap: round;
}
.x-progress-circle__num {
position: absolute;
inset: 0;
display: grid;
place-items: center;
color: #1b2028;
font-size: 18px;
font-weight: 700;
font-variant-numeric: tabular-nums;
}
.x-progress-circle__l {
color: #4b5563;
font-size: 13px;
font-weight: 700;
}
.x-progress-circle__svg--spin {
animation: x-progress-circle-turn 1s linear infinite;
}
@keyframes x-progress-circle-turn {
from {
transform: rotate(-90deg);
}
to {
transform: rotate(270deg);
}
}
/* 動きを減らす設定では回さない。「処理中」の文字で状態を伝える */
@media (prefers-reduced-motion: reduce) {
.x-progress-circle__svg--spin {
animation: none;
}
}
```
## 出力の約束
- HTML と CSS を分けて出す。JavaScript が要るときは素の JavaScript で書き、UIフレームワークは使わない。
- 参考実装がアイコンに Font Awesome のクラスを使っている場合は、プロジェクトで使っているアイコンかインライン SVG に置き換えてよい。
- 上のアクセシビリティ要件を満たす。満たせない箇所があるときは、理由を添えて先に知らせる。
- 色・角丸・余白は既存のデザイントークンがあればそれを使う。無ければ CSS 変数として切り出す。
使いどころ
- アップロードや同期の進み具合を、限られた場所(アイコンの上・カードの角など)に出したいとき
- ダッシュボードで、達成率を数字と一緒に目立たせたいとき
注意点
- プログレスバーと役目は同じで、細かい違いは読み取りにくい。横幅がとれるなら、長さを比べやすいプログレスバーを選ぶ
- ローディングスピナーは「待っている」ことだけを伝える。円形プログレスは、数字が分かるなら何%かを必ず出す
- 輪の長さだけでは何%か読み取れない。中央に数字を置く
アクセシビリティの要点
- role="progressbar" に aria-valuenow / aria-valuemin / aria-valuemax と名前(aria-labelledby など)を付ける。SVG は aria-hidden="true"
- 終わりが読めないときは aria-valuenow を付けない。これで不確定の進捗として伝わる
- 回る動きは prefers-reduced-motion で止め、「処理中」の文字で状態を伝える
- 輪の色と下地の境目を、非テキストのコントラスト(3:1)以上にする