`<wa-spinner>` の `--track-width` が正しく反映されない不具合を修正

shoelace-style/webawesome

<wa-spinner> コンポーネントで --track-width カスタムプロパティを指定しても、トラックとインジケーターの太さに反映されていなかった不具合が修正されました。あわせて、スピナーのサイズ・形状の計算がCSSカスタムプロパティを基準とした動的な算出方式に切り替えられています。

背景

--track-width<wa-spinner> のトラック(背景の円弧)とインジケーター(アニメーションする円弧)の線幅を制御するカスタムプロパティとして定義されていましたが、実際には機能していませんでした(#1317)。

SVGの <circle> 要素には cxcyrstroke-width がHTMLテンプレート内にハードコードされており(cx="25" cy="25" r="20" stroke-width="5")、CSSカスタムプロパティの値が描画に使われる余地がありませんでした。また、インジケーターの stroke-dasharraystroke-dashoffset も固定値(75, 100 / -5)だったため、円のサイズが変わっても破線の比率が崩れる構造上の問題も抱えていました。

この状況を受けて、#1316stroke-width のCSSスタイルを追加する代替案が提案されていましたが、本PRはより根本的な再設計として採用されました。

技術的な変更

SVGの幾何学的属性をHTMLテンプレートから除去し、CSSカスタムプロパティを用いた動的な計算に置き換えることで、--track-width の値が描画へ確実に反映されるようになりました。

spinner.ts(テンプレート)の変更:

SVGの viewBox 属性と <circle> 要素のすべての幾何学的属性がテンプレートから削除されました。

変更前:

<svg
  role="progressbar"
  aria-label=${this.localize.term('loading')}
  fill="none"
  viewBox="0 0 50 50"
  xmlns="http://www.w3.org/2000/svg"
>
  <circle class="track" cx="25" cy="25" r="20" fill="none" stroke-width="5" />
  <circle class="indicator" cx="25" cy="25" r="20" fill="none" stroke-width="5" />
</svg>

変更後:

<svg
  role="progressbar"
  aria-label=${this.localize.term('loading')}
  fill="none"
  xmlns="http://www.w3.org/2000/svg"
>
  <circle class="track" />
  <circle class="indicator" />
</svg>

spinner.styles.ts(スタイル)の変更:

新たに --size カスタムプロパティ(デフォルト 1em)が導入され、ホスト要素の幅・高さがこの値で制御されるようになりました。.track.indicator に共通するルールとして、cxcyrfillstroke-width をCSSで一括定義しています。

.track,
.indicator {
  --radius: calc(var(--size) / 2 - var(--track-width) / 2);
  --circumference: calc(var(--radius) * 2 * 3.141592654);

  cx: calc(var(--size) / 2);
  cy: calc(var(--size) / 2);
  r: var(--radius);
  fill: none;
  stroke-width: var(--track-width);
}

半径(--radius)の計算式 size / 2 - track-width / 2 は、円弧の描画がストロークの中心線を基準とするSVGの仕様に対応したものです。--track-width が大きくなるほど円弧が内側に寄るため、円弧が要素の枠からはみ出しません。

インジケーターの stroke-dasharraystroke-dashoffset も固定値から --circumference を使った動的な計算式に変わり、サイズや線幅に依らずアニメーションの見た目が一定に保たれます。

.indicator {
  stroke: var(--indicator-color);
  stroke-linecap: round;
  stroke-dasharray: calc(0.597 * var(--circumference)), calc(0.796 * var(--circumference));
  stroke-dashoffset: calc(-0.04 * var(--circumference));
  animation: dash 1.5s ease-in-out infinite;
}

テストも追加され、--track-width: 4px を指定したスピナーで .track.indicatorstrokeWidth がそれぞれ 4px として算出されることを検証しています。

設計判断

SVGの幾何学的属性をCSSへ移管するアプローチが採用されました。

SVGではプレゼンテーション属性(HTMLテンプレート上の cxr など)よりもCSSスタイルが優先されるという仕様上の特性を活かした設計です。属性をHTMLから除去してCSSで管理することで、CSSカスタムプロパティの変更がそのまま描画に反映される単一の制御経路が確立されます。あわせて viewBox を削除することで、SVGの座標系がCSS側の --size と完全に連動するようになっています。

また、stroke-dasharray の係数(0.5970.796)と stroke-dashoffset の係数(-0.04)は、変更前のハードコード値(75, 100 / -5)と円周に対する比率が一致するよう逆算されており、デフォルト表示の見た目を維持しながら動的計算に移行しています。

まとめ

本PRは、SVGの幾何学的属性をHTMLテンプレートからCSSカスタムプロパティ駆動の計算へ移管することで、--track-width の不具合を根本から解消しています。単なるバグ修正にとどまらず、スピナーの描画ロジック全体をCSSカスタムプロパティで一元管理できる構造へ再設計した点が、この変更の本質的な意義です。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
0b911c89

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文、背景、技術的な変更、設計判断、まとめの「総論→各論→結論」構成が明確で、ガイドラインを完全に満たしています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト、PR/Issue番号のリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

SVGやCSSカスタムプロパティに関する専門的な内容であり、対象読者であるエンジニアに適した技術レベルと表現です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論の構成であり、各段落はトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られており、非常に読みやすいです。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内のコード引用は、提供されたDiffの内容(ファイル名、追加・削除されたコード)と完全に一致しています。テストコードの変更内容についても正確に言及されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

SVGのプレゼンテーション属性やCSSカスタムプロパティなど、関連する技術用語が正確かつ適切に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

SVGのstroke描画仕様に基づいた半径の計算式や、`stroke-dasharray`の係数を逆算した説明など、技術的な解説が正確かつ論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張は、PRのタイトル、説明、特にDiff内のコード変更によって裏付けられています。ハルシネーションは見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#2235)、Issue番号(#1317)、コード内の具体的な数値(半径や`stroke-dasharray`の係数など)はすべて正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルはPRのタイトル「Fix `--track-width` not being applied correctly」の内容を正確に反映しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PR情報に基づかないバージョン情報やリリース日程などの外部知識は含まれておらず、信頼性が高いです。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「修正されました」といった過去形の表現が使われており、PRがマージ済みであるという時間関係を正確に反映しています。