`<wa-spinner>` の `--track-width` が正しく反映されない不具合を修正
<wa-spinner> コンポーネントで --track-width カスタムプロパティを指定しても、トラックとインジケーターの太さに反映されていなかった不具合が修正されました。あわせて、スピナーのサイズ・形状の計算がCSSカスタムプロパティを基準とした動的な算出方式に切り替えられています。
背景
--track-width は <wa-spinner> のトラック(背景の円弧)とインジケーター(アニメーションする円弧)の線幅を制御するカスタムプロパティとして定義されていましたが、実際には機能していませんでした(#1317)。
SVGの <circle> 要素には cx・cy・r・stroke-width がHTMLテンプレート内にハードコードされており(cx="25" cy="25" r="20" stroke-width="5")、CSSカスタムプロパティの値が描画に使われる余地がありませんでした。また、インジケーターの stroke-dasharray と stroke-dashoffset も固定値(75, 100 / -5)だったため、円のサイズが変わっても破線の比率が崩れる構造上の問題も抱えていました。
この状況を受けて、#1316 で stroke-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 に共通するルールとして、cx・cy・r・fill・stroke-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-dasharray と stroke-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 と .indicator の strokeWidth がそれぞれ 4px として算出されることを検証しています。
設計判断
SVGの幾何学的属性をCSSへ移管するアプローチが採用されました。
SVGではプレゼンテーション属性(HTMLテンプレート上の cx・r など)よりもCSSスタイルが優先されるという仕様上の特性を活かした設計です。属性をHTMLから除去してCSSで管理することで、CSSカスタムプロパティの変更がそのまま描画に反映される単一の制御経路が確立されます。あわせて viewBox を削除することで、SVGの座標系がCSS側の --size と完全に連動するようになっています。
また、stroke-dasharray の係数(0.597・0.796)と stroke-dashoffset の係数(-0.04)は、変更前のハードコード値(75, 100 / -5)と円周に対する比率が一致するよう逆算されており、デフォルト表示の見た目を維持しながら動的計算に移行しています。
まとめ
本PRは、SVGの幾何学的属性をHTMLテンプレートからCSSカスタムプロパティ駆動の計算へ移管することで、--track-width の不具合を根本から解消しています。単なるバグ修正にとどまらず、スピナーの描画ロジック全体をCSSカスタムプロパティで一元管理できる構造へ再設計した点が、この変更の本質的な意義です。