`<wa-button-group>` に要素が1つのときボーダー半径が失われるバグを修正

shoelace-style/webawesome

<wa-button-group> に子要素が1つだけ存在するとき、ボーダー半径がすべて消えて角丸のない四角形になるバグが修正されました。CSSセレクターに :not() 擬似クラスを加えるだけのシンプルな1行修正です。

背景

<wa-button-group> は複数のボタンを水平・垂直に並べ、グループの両端だけに角丸を残すUIコンポーネントです。グループ内では「先頭要素の右端を直角にする」「末尾要素の左端を直角にする」という処理で隣接する境界を揃えています。

#2367 で報告されたように、動的なUIの変更などで子要素が1つになるケースが生じます。このとき、その唯一の要素は :first-child:last-child の両方に同時に一致するため、4隅すべての半径が 0 に上書きされてしまっていました。

技術的な変更

button-group.styles.ts のスロットセレクターに :not() 擬似クラスを追加し、先頭かつ末尾でもある要素(=唯一の要素)への半径リセットを除外しました。

変更前:

:host([orientation='horizontal']) {
  ::slotted(:first-child) {
    --_button-start-end-radius: 0;
    --_button-end-end-radius: 0;
  }

  ::slotted(:last-child) {
    --_button-start-start-radius: 0;
    --_button-end-start-radius: 0;
  }
}

変更後:

:host([orientation='horizontal']) {
  ::slotted(:first-child:not(:last-child)) {
    --_button-start-end-radius: 0;
    --_button-end-end-radius: 0;
  }

  ::slotted(:last-child:not(:first-child)) {
    --_button-start-start-radius: 0;
    --_button-end-start-radius: 0;
  }
}

同様の修正が orientation='vertical' の4つのセレクターにも適用されており、合計4箇所のセレクターが変更されています。変更は純粋にCSS側の修正であり、コンポーネントのTypeScriptロジックには一切手が加わっていません。

設計判断

CSSの擬似クラスだけで問題を完結させるアプローチが採られました。子要素の数をJavaScriptでカウントして条件分岐するという選択肢もありますが、そのようなロジックは追加されていません。

CSS論理プロパティ(--_button-start-start-radius / --_button-start-end-radius / --_button-end-start-radius / --_button-end-end-radius)は書字方向(LTR/RTL)に依存しないインライン軸・ブロック軸ベースの命名になっており、垂直・水平どちらの orientation においても同一の変数セットを使い回せる設計です。今回の修正はその設計を壊さず、セレクターの精度を上げるだけで済んでいます。

まとめ

:first-child:not(:last-child):last-child:not(:first-child) という対称的なセレクター修正により、「唯一の子要素」が誤ったスタイルを受け取る問題を最小限の変更で解消しました。JavaScriptを使わずCSSセレクターの論理で完結させたことで、動的な要素数変化にも堅牢なスタイリングが実現されています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
97b5101b

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

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

「リード文→背景→技術詳細→設計判断→まとめ」の構成が明確で、総論→各論→結論の流れが理想的に実現されています。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライト、Issue/PR番号のリンク記法、いずれもガイドラインに準拠しており正確です。

対象読者への適合性 ✓ PASS

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

CSSの擬似クラスやコンポーネントの内部実装に関する内容で、専門知識を持つエンジニアという対象読者に完全に適合しています。

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

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

各セクション・各パラグラフが「総論→各論」の構成を保ち、トピックセンテンスが先頭に置かれているため、非常に高い可読性を確保しています。

Diff内容との照合 ✓ PASS

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

記事内で引用されているコード(変更前・変更後)は、提供されたDiff内容と完全に一致しています。ファイルパスも正確です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「::slotted」「CSS論理プロパティ」「:not()擬似クラス」などの技術用語が、文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

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

「唯一の要素が :first-child と :last-child の両方に一致する」というバグの原因説明や、:not() を使った解決策の解説が技術的に正確かつ論理的です。

事実の突合 ✓ PASS

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

記事内のすべての主張は、PRのタイトル、説明、およびDiff内のコードから裏付けられており、ハルシネーションは検出されませんでした。

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

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

PR番号(#2371)、Issue番号(#2367)といった固有名詞はすべて正確に記載されています。

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

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

記事のタイトルは、PRのタイトル「Fix <wa-button-group> border radius when only one item is present」の内容を的確に日本語で表現しています。

外部知識の正確性 ✓ PASS

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

PR情報に記載のないバージョン情報やリリース予定など、外部知識に基づく記述は一切含まれていません。

時間表現の正確性 ✓ PASS

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

記事内には時間表現に関する記述がなく、PR情報との不整合は発生していません。