課題と範囲
ボタンをクリックすると、メニュー、ヒント、またはコマンドパネルが開きます。ポップオーバーはボタンの近くにとどまり、スペースがない場合は反転し、ビューポートやスクロールコンテナによるクリッピングを回避し、キーボードフォーカスと閉じ操作をサポートする必要があります。JavaScript による座標計算と CSS Anchor Positioning を比較し、プログレッシブエンハンスメントを提案してください。
MDN では、アンカーポジショニングを position-try などのフォールバックメカニズムを用いて要素を別の要素に対して相対配置するものとして説明しています。Chrome のガイドでは、anchor-name と position-anchor による関係性が示されています。優れた回答では、レイアウト、スクロール、ブラウザサポート、およびインタラクションセマンティクスを包括して網羅します。
面接官が評価するポイント
- 視覚的な配置、DOM セマンティクス、およびフォーカス管理を明確に分離しているか。
- プロパティ名を暗記しているだけでなく、アンカー関係とフォールバック候補を理解しているか。
- スクロールコンテナ、クリッピング、スタッキングコンテキストについて論理的に考察できているか。
- CSS 機能が利用できない場合に、最小限の JavaScript フォールバックを設計できるか。
- ブラウザ、入力方法、アクセシビリティのテストマトリクスを定義しているか。
フロントエンドの面接では、ブラウザのレイアウトの基礎、保守可能なコンポーネント、エッジケースの処理がよくテストされます。優れた回答は、普遍的なサポートを前提とするのではなく、実際の互換性やプロダクトの制約の中に新しい CSS 機能を位置づけます。
回答前の確認質問
- ポップオーバーはメニュー、ツールチップ、ダイアログのどれですか?セマンティックロールによってフォーカスと Escape キーの動作が変わります。
- 参照要素はボタン、アイコン、リストアイテムのどれですか?移動したり仮想化されたりしますか?
- スクロールコンテナを飛び出す必要がありますか?クリッピングを避けるためにトップレベルのレンダリングレイヤーが必要ですか?
- どのブラウザと WebView をサポート対象としますか?フォールバックでもすべての動作を維持する必要がありますか?
- 移動時にアニメーションが必要ですか?ユーザーが視覚効果の抑制(reduced motion)を設定している場合はどうしますか?
30秒の回答フレームワーク
まず、ポップオーバーのセマンティクスとフォーカスモデルを定義します。次に、ボタンをアンカーとして命名し、ポップオーバーをそれに関連付けます。デフォルトでは下部に配置し、上部や側面に順序付けられた position-try フォールバックを提供します。単一の固定オフセットには依存しません。未対応のブラウザには、軽量なポジショニングアダプターまたはインラインフォールバックを使用し、同一のアクセシビリティテストで検証します。
ステップごとの詳細な回答
ステップ 1: セマンティクスとフォーカスを最優先で処理する
メニューにはフォーカス可能なメニュー項目と明示的な展開状態が必要です。ツールチップには必須のアクションを含めてはなりません。複雑なコマンドパネルはダイアログのように動作する場合があります。開く際にはトリガーを記録し、閉じる際にはフォーカスを復元します。Escape キーおよび外部クリックのルールは一致している必要があります。CSS は配置を制御しますが、これらのインタラクションの保証は制御しません。
ステップ 2: アンカー関係を確立する
トリガーをアンカーとして命名し、ポップオーバーの position-anchor にそれを指定します。複数のリストアイテムが1つの名前を共有しないよう、関係を安定的またはインスタンススコープに保ちます。コンポーネントの破棄、再利用、仮想スクロールの際には、古くなった関連付けをクリアする必要があります。
ステップ 3: デフォルト位置とフォールバック位置を定義する
一般的な「トリガーの下」の位置を宣言し、次に上、開始側(start-side)、終了側(end-side)の候補をリストします。候補の順序は、コンテンツを縮小する前に水平方向の配置を維持するなど、プロダクトの優先順位を表現します。position-try メカニズムを使用してブラウザに適切な候補を選択させ、デバッグ用に失敗した候補を特定できるようにします。
ステップ 4: 境界とスクロールを処理する
スクロールコンテナ、transform が適用された祖先要素、新しいスタッキングコンテキストによるクリッピングを確認します。ポップオーバーがコンテナの境界を越える必要がある場合は、インスタンスレベルのアンカー関係を保持したまま、トップレベルレイヤーにレンダリングします。トリガーがビューポートから外れた場合、ネストされたコンテナ、および右から左(RTL)のテキストにおけるスクロールとズームをテストします。
ステップ 5: プログレッシブエンハンスメントを維持する
機能検出の後に CSS 配置を使用し、JavaScript アダプターは必要な場合にのみアクティブにします。アダプターはトリガーの矩形を読み取り、候補を評価し、必要なスクロール、サイズ、レイアウトのシグナルのみを監視します。両方の実装が同時に位置スタイルを書き込まないようにしてください。競合してちらつきが発生する原因になります。
ステップ 6: サイズとコンテンツを制限する
最大幅と最大高さ、パディング、内部スクロール領域を定義します。候補の選択では、利用可能なスペースと最小の可読サイズを考慮する必要があります。長いコンテンツはページから溢れさせるのではなく、ポップオーバー内部でスクロールさせるべきです。初期測定値が古くなる可能性があるため、動的コンテンツの読み込み後に再評価します。
ステップ 7: モーションと入力デバイスを処理する
位置の変更には明示的な所要時間を設定し、reduced-motion のパスを用意します。キーボード、タッチ、ポインター入力は、開閉およびフォーカスのルールを共有する必要があります。ホバーによるツールチップはキーボードでアクセス可能なヘルプの代わりにはなりません。アニメーションによってフォーカスの復元が遅れたり、支援技術に誤った状態を伝えたりしてはなりません。
ステップ 8: 検証マトリクスを構築する
デフォルト位置、各フォールバック、狭いビューポート、ネストされたスクロール、ズーム、RTL テキスト、長いコンテンツ、動的コンテンツ、未対応ブラウザをテストします。クリッピングがないこと、トリガーとコンテンツの正しい関係、Escape による破棄、フォーカスの復元、アクセシビリティツリーの一貫した状態を検証します。ワイドスクリーンのスクリーンショットで妥協せず、CSS パスとフォールバックパスの両方を比較します。
模範回答
まずメニュー、ツールチップ、ダイアログのセマンティクスを区別し、フォーカスと閉じ動作を確立します。トリガーにアンカー名を付与し、ポップオーバーは position-anchor を使用してデフォルトを下部に設定し、上部および側面に position-try フォールバックをリストします。スクロールコンテナによってクリップされる場合は、インスタンスの関係を保持したままトップレベルレイヤーにレンダリングします。未対応のブラウザには同一のセマンティクスを持つ1つの JavaScript アダプターを使用します。狭いビューポート、ネストされたスクロール、RTL テキスト、動的コンテンツ、キーボード、スクリーンリーダーをテストし、reduced-motion にも配慮します。
よくある間違い
- 座標の計算を一度しか行わない → スクロールやズームで配置が崩れる → CSS やアダプターがレイアウト変更に反応するようにする。
- ツールチップをメニューのように扱う → キーボードや支援技術が機能しなくなる → セマンティクスとフォーカスを最優先で定義する。
- 下部への配置しか用意しない → ビューポートの端で溢れる → 複数の候補を順序立てて設定する。
overflow: hiddenを無視する → 祖先要素がポップオーバーをクリップする → 適切なトップレベルのレンダリング境界を選択する。- CSS と JavaScript の両方で配置を行う → 競合やちらつきが発生する → 機能検出後に正確に一方のパスのみを有効化する。
- マウスを使ったワイドスクリーンのみでテストする → モバイルやキーボードで破綻する → 入力デバイス、文字方向、アクセシビリティを網羅する。
フォローアップ質問と回答
Anchor Positioning はすべてのフローティング要素ライブラリを置き換えられますか?
いいえ。レイアウト関係とフォールバック配置を処理するものであり、フォーカス、ロール、破棄、ドラッグ、複雑なビジネス衝突ルールは処理しません。コンポーネントには依然としてインタラクション層と互換性層が必要です。
スクロールコンテナがポップオーバーをクリップする場合はどうしますか?
境界を越える必要があるかどうかを判断します。必要な場合は、インスタンス関係を持たせたトップレベルのレンダリングレイヤーを使用します。不要な場合は、候補を制限し、コンテナ内でコンテンツをスクロールさせます。
リスト内での anchor-name の衝突をどのように回避しますか?
インスタンスごとに安定した関係を生成するか、コンポーネントのライフサイクルで名前を管理します。仮想化されたノードが再利用される際に、関連付けをクリアします。
CSS がサポートされていない場合のフォールバックは何ですか?
機能検出を使用して、同一のセマンティクス、フォーカス、破棄動作を持つ1つの JavaScript ポジショニングアダプターを有効にします。重要度の低いコンテンツの場合、トリガーの下のインラインブロックにすることがさらにシンプルなフォールバックになります。
動的コンテンツによって位置が変わる場合はどうしますか?
サイズ変更によってレイアウトが再実行されるようにします。フォールバックパスでは、必要なサイズとスクロールのシグナルのみを監視します。固定のタイムアウトで不安定なレイアウトをごまかさないようにします。
フォールバック候補が正しく機能することをどう証明しますか?
各エッジで再現可能なビューポートとスクロール状態を作成し、CSS クラス名を確認するのではなく、最終的な配置、クリッピング、可読サイズ、アンカーからの距離をアサートします。
JavaScript のフローティングライブラリを今でも選択するのはどのような場合ですか?
広範なブラウザサポート、高度な衝突ルール、ドキュメントを跨ぐ配置、または成熟したアクセシビリティ動作が、ネイティブ CSS パスの利点を上回る場合に選択します。CSS はプログレッシブなレイアウト層として残すことができます。