`<wa-select multiple>` のパディング不整合をCSS `:has()` で修正
タグが表示されている状態の <wa-select multiple> で、ブロック方向とインライン方向のパディングに不整合が生じていた問題を修正しました。プライベートカスタムプロパティと CSS :has() セレクタを活用し、タグの有無に応じた動的なパディング制御を実現しています。
背景
複数選択コンポーネントでタグを表示する際、パディングの計算方法がブロック方向とインライン方向で統一されていなかったため、テーマによっては視覚的な不整合が明確に現れていました。この問題は多くのテーマでは目立たないものの、Playful テーマのように独自のフォームコントロール高さを持つテーマでは顕著に現れます。
同様の問題は <wa-combobox multiple> でも発生しており、webawesome-pro#164 で先行して修正が入っていました。今回はその同じアプローチを <wa-select multiple> にも適用したものです。
技術的な変更
今回の修正の核心は、プライベートカスタムプロパティ --_padding-with-tags の導入と、CSS :has() セレクタによるタグ存在検知の組み合わせです。
変更前: .select:not(.placeholder-visible) というクラスベースのセレクタで .combobox のパディングを調整し、JavaScript 側で placeholder-visible クラスを管理していました。ブロック方向のパディングのみを計算式で指定し、インライン方向は padding-inline-start: 0 でリセットする方式でした。
// 変更前
:host([multiple]) .select:not(.placeholder-visible) & {
padding-inline-start: 0;
padding-block: calc(var(--wa-form-control-height) * 0.1 - var(--wa-form-control-border-width));
}
変更後: :has(.tags wa-tag) セレクタでタグの存在を直接 CSS で検知し、ブロック・インラインの両方向に同じ計算値を適用します。計算式は --_padding-with-tags として一元化されています。
// 変更後
:host([multiple]) {
--_padding-with-tags: calc(var(--wa-form-control-height) * 0.1 - var(--wa-form-control-border-width));
& .combobox:has(.tags wa-tag) {
padding-block: var(--_padding-with-tags);
padding-inline-start: var(--_padding-with-tags);
}
}
この変更に伴い、.start スロットのマージン調整も更新されています。タグ表示時は .combobox 自体に padding-inline-start が適用されるため、.start のスロットコンテンツは差し引いた値を適用します。
/* 変更前 */
:host([multiple]) .start::slotted(*) {
margin-inline: var(--wa-form-control-padding-inline);
}
/* 変更後 */
:host([multiple]) .combobox:has(.tags wa-tag) .start::slotted(*) {
margin-inline-start: calc(var(--wa-form-control-padding-inline) - var(--_padding-with-tags));
}
JavaScript 側では、placeholder-visible クラスの付与に使用していた isPlaceholderVisible 変数と、そのクラスを classMap に渡す処理が削除されました。タグの有無の判定が CSS :has() に移管されたことで、JavaScript のテンプレート処理が2行分シンプルになっています。
設計判断
状態管理をJavaScriptからCSSへ移管するアプローチが採用されました。
従来の placeholder-visible クラスは JavaScript でコンポーネントの状態を評価し、クラスとして DOM に付与することで CSS に伝達する方式でした。今回の変更では、タグの存在という状態を CSS の :has(.tags wa-tag) が直接 DOM を観察して判定します。これにより、状態変化のたびに再レンダリングが必要だった仕組みから、CSS エンジンが自律的に適用条件を評価する仕組みへと変わっています。
また、tags コンテナへの margin-inline-start: 0.25em が削除され、代わりに .combobox 全体の padding-inline-start で空間を確保する設計に統一されました。パディングの計算ロジックを --_padding-with-tags という単一の変数に集約することで、ブロックとインラインの両方向で同じ値が使われることが保証されています。
まとめ
JavaScript の状態クラスと CSS のパディングリセットという2つの仕組みが絡み合っていた実装を、CSS :has() セレクタとプライベートカスタムプロパティによる宣言的なスタイル制御に置き換えた変更です。パディング値の一元管理によりブロック・インライン方向の整合性が保証され、テーマ間での見た目の差異が解消されています。