アイコンボタンにキャレットを付与した際の幅崩れを修正
<wa-button> のアイコンボタンに with-caret 属性を付与すると、Firefoxでキャレットがボタン外にはみ出す表示崩れが発生していました。CSSセレクタの変更と aspect-ratio の上書きにより、この問題が解消されました。
背景
アイコンボタンはその性質上、幅と高さを1:1の正方形に保つ必要があります。そのため button.styles.ts では .button.is-icon-button に aspect-ratio: 1 が設定されており、アイコン単体での表示は正しく機能していました。しかし、with-caret 属性を追加すると、ボタン内のコンテンツ(アイコン+キャレット)が1:1の制約に収まらず、Firefoxではキャレットが正方形の枠からはみ出す問題が発生していました。
この問題はFirefoxのみで視覚的に顕在化していたとPRに記載されています。
技術的な変更
button.styles.ts の .button.is-icon-button:has(wa-icon) セレクタが .button.is-icon-button.caret に変更され、合わせて aspect-ratio と min-width の指定が追加されました。
変更前:
.button.is-icon-button:has(wa-icon) {
width: auto;
}
変更後:
/* Icon buttons with a caret need to grow to fit both the icon and the caret */
.button.is-icon-button.caret {
width: auto;
aspect-ratio: auto;
min-width: var(--wa-form-control-height);
}
変更のポイントは3つです。まず、セレクタを :has(wa-icon) から .caret クラスへ変更し、キャレットが存在する場合のみこのルールが適用されるようにしています。次に、aspect-ratio: auto で親の aspect-ratio: 1 を上書きし、正方形の制約を解除しています。最後に、min-width: var(--wa-form-control-height) を追加することで、キャレットが付いてもボタンの幅がゼロや極端に小さくなることを防ぎ、アイコン単体分の最低幅を保証しています。
これにより、キャレットなしのアイコンボタン(.button.is-icon-button)には従来の aspect-ratio: 1 が引き続き適用され、キャレットありのボタンのみ幅が内容に合わせて伸長します。
設計判断
セレクタの対象をキャレット有りのケースに限定するアプローチが採用されました。
変更前の :has(wa-icon) セレクタは「wa-icon を含む場合に width: auto にする」という意図でしたが、このルールの適用対象はキャレットの有無に関わらずアイコンを持つすべてのボタンに及んでいました。一方、aspect-ratio を崩す必要があるのはキャレットが存在する場合だけです。.caret クラスへの変更は、意図の変化(「アイコンを持つ」から「キャレットを持つ」)をセレクタに正確に反映させており、副作用の範囲を必要最小限に絞っています。
min-width にフォームコントロール高さのCSS変数 --wa-form-control-height を使用することで、ボタンサイズのバリアントに応じて最低幅も追従する設計になっています。
まとめ
CSSの aspect-ratio と :has() の組み合わせが想定外の表示崩れを引き起こすケースへの対処として、適用対象を正確なセレクタで絞り込みつつ aspect-ratio: auto で制約を解除するパターンが示されています。変更行数は最小限ながら、セレクタの意図とCSS変数の活用により保守性を維持した修正といえます。