`label` スロット使用時のスライダースタイリングを属性指定と統一
フォームコントロールの label 属性と label スロットで、見た目が異なっていた問題を修正しました。スライダーを含むフォームコントロールで、両方の指定方法が同一のスタイルで表示されるようになります。
背景
#2124 で報告されたとおり、Web Awesomeのスライダーコンポーネントでは、ラベルの指定方法によって見た目が異なるという不整合が存在していました。label 属性で指定した場合と label スロットにコンテンツを置いた場合とで、タイポグラフィのスタイルとスライダートラック上部のスペースが一致していませんでした。
Web Awesomeのフォームコントロール(スライダー、インプット、セレクトなど)は、ラベルを label 属性またはスロットの2通りの方法で設定できます。この柔軟性は意図された設計ですが、スタイリングの統一がなされておらず、利用方法によって視覚的な差異が生じていました。
技術的な変更
変更の核心は slider.styles.ts における CSS セレクタの修正です。スロットにコンテンツが存在するかを判定するセレクタが、クラスベースのアプローチに置き換えられました。
変更前:
/* Add extra space between slider and label, when present */
#label:has(*:not(:empty)) ~ #slider {
&.horizontal {
margin-block-start: 0.5em;
}
変更後:
/* Add extra space between slider and label, when present */
#label.has-label ~ #slider {
&.horizontal {
margin-block-start: 0.5em;
}
変更前のセレクタ :has(*:not(:empty)) はスロットに直接子要素が存在する場合のみを検出します。一方、has-label クラスはコンポーネント側(JavaScript)でラベルの有無を統一的に判定して付与されるため、label 属性とスロットの両方をカバーできます。この修正により、スライダートラック上部の 0.5em のマージンがどちらの指定方法でも一様に適用されるようになります。
設計判断
CSSの:has()擬似クラスによるDOM状態の検出から、JavaScriptが付与するクラスへの依存へと方針が転換されています。
:has(*:not(:empty)) はスロットの実際のDOM構造を直接参照するアプローチです。これはスロットコンテンツのみを対象とし、label 属性で設定されたラベルは考慮しません。対して has-label クラスはコンポーネントのロジックレイヤーで「ラベルが存在するかどうか」を一元的に判断した結果をCSSに伝える設計です。属性とスロットのどちらでラベルが設定されても、同じクラスが付与されます。
このアプローチにより、スタイリングの条件判断をCSSとJavaScriptのどちらで行うかが明確に役割分担されます。ラベルの存在判定はコンポーネントロジックが担い、CSSはその結果を受け取ってスタイルを適用するだけに徹しています。
まとめ
セレクタを1行修正するだけの小さな変更ですが、CSSがDOMの内部構造を直接観察するのではなく、コンポーネントロジックが設定したクラスを参照するという設計の整合性を取り戻しています。label 属性とスロットという2つのAPIを等価に扱うという一貫性が、この修正で担保されました。