ポップオーバーの配置方向別ビューポート制約を追加
モバイル端末などの狭い画面でポップオーバーがビューポートからはみ出す問題を、配置方向ごとに適切なサイズ制約とマージンを設けることで解決しました。
背景
狭い画面でポップオーバーが正しく収まらない問題が #2333 で報告されていました。先行する #2375 で初期対応が行われたものの、コメント中の議論で残課題が確認され、本PR #2379 がその追加修正として作成されました。
問題の核心は、ポップオーバーが上下に配置される場合は横幅がビューポートを超えうること、左右に配置される場合は縦高さがビューポートを超えうることです。これらは配置軸が異なるため、単一のルールでは対処できません。
配置方向の違いに応じた制約を個別に定義することで、両ケースを正しくカバーできる設計に落ち着いています。
技術的な変更
popover.styles.ts に、data-current-placement 属性の値に基づいて配置方向を判定し、方向ごとに異なる制約を適用するCSSルールが追加されました。
上下配置(top / bottom)の場合、ポップオーバーが水平方向にシフトする可能性があるため、横幅と水平マージンを制御します。
+ /* Reserve a small visual gap between the popover and the viewport edge on the axis where the popup can shift. */
+ .popover[data-current-placement^='top'] .body,
+ .popover[data-current-placement^='bottom'] .body {
+ max-width: min(var(--max-width), 100vw - (var(--wa-space-m) * 2));
+ margin-inline: var(--wa-space-m);
+ }
+
+ .popover[data-current-placement^='left'] .body,
+ .popover[data-current-placement^='right'] .body {
+ max-height: calc(100vh - (var(--wa-space-m) * 2));
+ margin-block: var(--wa-space-m);
+ }
上下配置の max-width には min(var(--max-width), 100vw - (var(--wa-space-m) * 2)) が使われています。min() 関数により、--max-width カスタムプロパティで指定された幅と、ビューポート幅からマージン両側分(--wa-space-m * 2)を引いた値の小さい方が採用されます。画面が十分広い場合は --max-width が、狭い場合はビューポート基準の制約が自動的に有効になる仕組みです。
左右配置(left / right)では、ポップオーバーが垂直方向にシフトするため、対象軸は高さになります。max-height に calc(100vh - (var(--wa-space-m) * 2)) を設定し、margin-block で上下に余白を確保しています。
設計判断
配置軸に応じて制約対象(幅 vs 高さ)を切り替える方式 が採用されています。
ポップオーバーの位置調整(シフト)はアンカー要素に対して配置軸と垂直な方向に行われます。上下配置なら水平シフト、左右配置なら垂直シフトです。制約を掛けるべきは「シフトが発生する軸」であり、本変更はこの関係を正確に反映した実装になっています。
data-current-placement の属性セレクタで前方一致(^=)を使用している点も重要です。top-start・top-end といったバリアントを個別に列挙せず、top で始まる全パターンをまとめて捕捉することで、ルールを簡潔に保っています。
また、--max-width カスタムプロパティは上書きしておらず、min() による比較に留めることでユーザー定義の最大幅指定を尊重しています。この設計は #2375 で確立された方針を踏襲するものです。
まとめ
本変更は、配置方向という文脈に応じて制約軸を切り替えるという明快な原則のもと、最小限のCSSで上下・左右すべての配置パターンを網羅しています。min() と前方一致セレクタを組み合わせることで、カスタムプロパティとの後方互換性を保ちつつ、狭いビューポートでのポップオーバー表示の堅牢性が高まりました。