`<wa-select multiple>` のパディング不整合をCSS `:has()` で修正

shoelace-style/webawesome

タグが表示されている状態の <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() セレクタとプライベートカスタムプロパティによる宣言的なスタイル制御に置き換えた変更です。パディング値の一元管理によりブロック・インライン方向の整合性が保証され、テーマ間での見た目の差異が解消されています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
3e45b627

この記事は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リンク記法の正確性

ファイル名付きシンタックスハイライト(```typescript:path/to/file.ts)や、PR番号のリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

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

CSSカスタムプロパティや:has()セレクタ、コンポーネントの状態管理といったトピックを扱っており、専門知識を持つエンジニアという対象読者に適合した内容です。

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

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

各セクションが総論→各論の構成になっており、各段落もトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られています。これにより、記事の骨子が掴みやすくなっています。

Diff内容との照合 ⚠ WARNING

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

主要なコード変更はDiffと一致していますが、変更前のコードブロックの引用(:host([multiple]) .select:not(.placeholder-visible) & { ... })が、元のネスト構造を省略した結果、セレクタの文法として若干不正確になっています。ただし、意図は伝わるため、理解を大きく妨げるものではありません。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`:has()`セレクタ、プライベートカスタムプロパティ、スロットなどの技術用語が、文脈に応じて正確かつ適切に使用されています。

説明の技術的正確性 ✓ PASS

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

CSSの変更がパディングの不整合をどのように解決するのか、またJavaScript側のロジックが不要になった理由など、技術的な説明はDiffの内容と一致しており、論理的で正確です。

事実の突合 ✓ PASS

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

記事内の主張はすべてPRのTitle, Description, Diffの内容で裏付けられており、ハルシネーションは見られません。「Playfulテーマで問題が顕著になる」点や「先行修正がある」点など、PRの文脈を正確に反映しています。

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

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

PR番号(#2177)や、言及されている外部PR番号(webawesome-pro#164)など、記事内の数値や固有名詞はすべて正確です。

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

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

記事のタイトルはPRのタイトル「Fix <wa-select multiple> padding」の内容を、`:has()`という具体的な解決策を含めて表現しており、主題は完全に一致しています。

外部知識の正確性 ✓ PASS

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

記事の内容はすべて提供されたPR情報に基づいており、サポート状況やリリース予定といったPR外の知識の追記はありません。

時間表現の正確性 ✓ PASS

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

「先行して修正が入っていました」といった時間表現は、PR Descriptionの記述と一致しており、正確です。