ドロップダウンとメニューシステム
目的
ドロップダウンとメニューシステムスキルは、Webインターフェース全体でフローティングアクションメニュー、オーバーフローメニュー、コンテキストメニュー、カスケードサブメニューを設計するための標準化されたフレームワークを提供します。ドロップダウンメニューは、アイコンボタン、スプリットボタン、コンテキストアクションなどのトリガー要素にアタッチされた、インタラクティブなコマンド、オプション、副アクションの整理されたリストを表示します。
効果的なドロップダウンメニューシステムを設計するには、空間レイアウト、視覚的階層、アイテムのグループ化、キーボードナビゲーションセマンティクス、衝突処理(ビューポート境界)、およびタッチベースのモバイルビューポートでのレスポンシブ適応のバランスを、ユーザーを混乱させたりWCAG 2.1 AAアクセシビリティガイドラインに違反したりすることなく取る必要があります。
ユースケース
- アクション&オプションメニュー: データテーブル、カード、ページヘッダー内のトリガーボタンにアタッチされたセカンダリページまたは行アクション(例:「編集」「複製」「エクスポート」「削除」)を表示します。
- オーバーフロー&その他のメニュー: コンテナスペースが限られている場合(例:ツールバーやテーブルヘッダーの「...」ボタン)、優先度の低いツールやナビゲーションリンクを収容します。
- コンテキストポップアップメニュー: 特定のビジュアルキャンバスやリストアイテムを右クリックまたは長押しすると、ターゲットを絞ったコンテキストコマンドを表示します。
- カスケードサブメニュー: マルチレベルのメニューオーバーレイ内で、ネストされたアクションまたはマルチレベルのカテゴリオプションを整理します。
- 選択アクションメニュー(チェック可能&ラジオアイテム): フローティングアクションパネル内で、ビューステート、列の表示、並べ替え設定を切り替えます。
使用すべきでない場合
- フォーム選択入力(コンボボックス&セレクト入力): ユーザーがフィールドに入力するために1つまたは複数の値を選択するフォーム入力(例:国や製品カテゴリの選択)の場合は、
custom-select-and-combobox-systemを使用します。 - 高密度ナビゲーションパネル: 構造化されたカテゴリ、ランディングページ、マーケティングプロモーションを含むマルチカラムのグローバルサイトナビゲーションの場合は、
mega-menu-navigation-systemを使用します。 - 大規模モーダル&タスクワークスペース: 複雑なサブタスク、マルチフィールド編集、フォーカスを維持する必要のあるマルチステップウィザードフォームの場合は、
overlay-and-dialog-systemまたはbottom-sheet-design-systemを使用します。 - コンテキストヘルプ&ツールチップ: 要素の機能を説明する非インタラクティブなホバー/フォーカステキスト説明の場合は、
tooltip-and-hint-systemを使用します。
入力
- トリガーコンポーネントとジオメトリ: プライマリトリガー要素のタイプ(標準ボタン、アイコンボタン、スプリットボタン、または右クリックターゲット領域)と空間配置。
- メニューアイテムインベントリと階層: アクション、アイテムタイプ(標準、チェック可能、ラジオ、破壊的)、アイコン、キーボードショートカット、セパレーター、セクショングループラベルのリスト。
- サーフェスとエレベーショントークン:
elevation-and-depth-systemとaccessible-color-systemからの背景サーフェスカラー、境界線スタイル、ドロップシャドウトークン(--elevation-popover)、z-index配置(--z-popover)。 - ビューポートとデバイスコンテキスト: デバイスの向き、画面幅のブレークポイント、タッチサポートの特性。
出力
- メニュー構造とレイアウト設計図: メニューコンテナのサイズ、パディング、アイテムの配置、後続のショートカットヒント、セクション区切りスペースに関するCSSおよびHTML構造仕様。
- 空間配置と衝突戦略: アンカー配置(上/下/左/右)、配置、動的な反転/スライドロジック、最大高さスクロール可能な境界のためのレイアウトルール。
- レスポンシブモバイル適応モデル: デスクトップの狭いドロップダウンポップオーバーを、モバイルビューポートでボトムアクションシート(
bottom-sheet-design-system)または全幅タッチリストに変換する設計仕様。 - ARIAとキーボードナビゲーション仕様: ARIAロール(
role="menu"、role="menuitem"、role="menuitemcheckbox"、role="menuitemradio")、展開状態(aria-expanded)、および矢印キーフォーカス管理をカバーするプログラムによるアクセシビリティルール。
ワークフロー
1. メニュー構造とアイテム構造を定義する
メニュー内のアイテムを論理的な機能グループに分類して、スキャンしやすさを最大化します:
- ヘッダーとセクションラベル: 大文字のマイクロタイポグラフィまたは控えめなセクションヘッダー(
font-size: 0.75rem、font-weight: 600、letter-spacing: 0.05em)を使用して、関連アクションをグループ化します。 - 標準アイテム構成: flexboxを使用して要素を水平に配置します(
gap: 0.75rem):- 先頭グラフィック: アクションの目的を明確にする16x16pxまたは20x20pxのアイコン。
- ラベルテキスト: 簡潔でアクション指向の動詞(例:「PDFをダウンロード」「アイテムを複製」)。
- 末尾のショートカットヒント: 等幅フォントのキーボードショートカットテキスト(例:
⌘E、Ctrl+D)は、視覚的に控えめにします(color: var(--text-tertiary))。 - 末尾のシェブロン: カスケードサブメニュートリガーを示します(
>)。
- 特殊アイテムタイプ:
- チェック可能アイテム(
role="menuitemcheckbox"): アクティブなときに先頭にチェックマークを表示します。 - ラジオアイテム(
role="menuitemradio"): グループ内で選択されている場合にラジオドットを表示します。 - 破壊的アイテム: 「削除」「除去」などのネガティブアクションを、異なる警告色トークン(
color: var(--color-danger))でスタイル設定し、視覚的な区切り線で良性のアクションと分離します。
- チェック可能アイテム(
- 区切り線(
role="separator"): 控えめな水平ルール(1px solid var(--border-subtle))を使用して、異なるアクショングループを区分します(例:ビューアクションを編集/削除アクションから分離)。
2. 空間配置と衝突処理を確立する
メニューがトリガーの隣にきれいにレンダリングされ、画面端からはみ出さないようにレイアウトルールを設定します:
- アンカー配置: メニューポップオーバーをトリガーボタンの境界に対して相対的に配置します:
- 左下 / 右下: トリガーボタンの下にデフォルトで配置します。トリガーが画面の右端の近くにある場合は、右端に合わせます(例:データテーブルの行アクション列)。
- 左上 / 右上: ビューポートの下部に近い場合、トリガーボタンの上に方向を反転します。
- ビューポート衝突と反転ルール:
- 画面端から最低 12pxのマージン を維持します(
viewport-margin: 12px)。 - 最大高さ制約(
max-height: calc(100vh - 32px))を設定し、長いメニューには内部垂直スクロール(overflow-y: auto)を設けます。
- 画面端から最低 12pxのマージン を維持します(
- エレベーショントークン: フローティングメニューを背景のテーブル行やカードから視覚的に分離するために、最前面スタッキング(
z-index: var(--z-popover))とドロップシャドウ(box-shadow: var(--shadow-popover))を適用します。
3. インタラクションとサブメニューの動的動作を設定する
- トリガーステート: トリガーボタンがアクティブなオープンステートを示すために、
aria-expanded="true"と控えめな押下視覚ステート(background-color: var(--bg-hover))を使用するようにします。 - サブメニューのホバーとキーボード遅延:
- カスケードサブメニューは、マウスホバー時に意図的な遅延(150~200msの意図タイマー)で開き、ポインター移動中の誤ったトリガーフラッシュを防ぎます。
- サブメニュートリガーで
ArrowRightを押すとサブメニューが展開され、フォーカスが内部に移動します。ArrowLeftはサブメニューを閉じて、フォーカスを親メニューアイテムに戻します。
- 消去トリガー: 以下の場合に開いているメニューオーバーレイを消去します:
- ユーザーがメニューパネルの外側をクリックした場合(クリック外部リスナー)。
- ユーザーが
Escapeキーを押した場合。 - アクティブなメニューアイテムアクションが実行された場合(チェック可能なトグルアイテムである場合を除く)。
- フォーカスがメニューオーバーレイから外れた場合。
4. レスポンシブモバイル適応を設計する
デスクトップのフローティングドロップダウンポップオーバー(例:220pxのフローティングボックス)は、タップターゲットが小さく正確な配置が必要なため、モバイルタッチスクリーンではパフォーマンスが低下します:
- モバイルタッチ変換(
< 768px):- デスクトップポップオーバーを、ビューポート下部に固定された ボトムアクションシート(
bottom-sheet-design-system)に変換します。 - アイテムの行の高さを、最小タップターゲット 44px(できれば48px)に、全幅の水平タップゾーンで増やします。
- 親指での簡単な消去のために、シートの下部に明示的な視覚的ドラッグハンドルまたは明確な「キャンセル」ボタンを提供します。
- デスクトップポップオーバーを、ビューポート下部に固定された ボトムアクションシート(
- タッチフィードバック: 即時の触覚フィードバックのために、明確なアクティブタッチ背景状態(
:active)を適用します。
5. アクセシビリティとキーボードセマンティクスをプログラムする
- ARIAランドマークとロールマッピング:
- トリガーボタンの設定:
aria-haspopup="menu"、aria-expanded="true|false"、aria-controls="menu-id"。 - メニューコンテナの設定:
role="menu"、aria-labelledby="trigger-id"、tabindex="-1"。 - メニューアイテムの設定:
role="menuitem"、role="menuitemcheckbox"、またはrole="menuitemradio"。
- トリガーボタンの設定:
- キーボードナビゲーションモデル:
- トリガーで
Enter/Space/ArrowDown:メニューを開き、最初のメニューアイテムにフォーカスを移動します。 ArrowDown/ArrowUp:メニューアイテムを順にフォーカス移動します(先頭から末尾にラップアラウンド)。Home/End:最初または最後のメニューアイテムに直接フォーカスを移動します。Escape:メニューをすぐに閉じ、フォーカスをトリガーボタンに戻します。Tab:メニューをすぐに閉じ、標準のドキュメントフォーカス進行を許可します。- タイプアヘッド文字検索: 文字キー(例:「D」)を押すと、その文字で始まる次のメニューアイテムに直接フォーカスを移動します。
- トリガーで
決定ルール
メニュータイプとコンテキスト選択
| コンテキスト / 目標 | 推奨パターン | ARIA構造 | モバイル適応 |
|---|---|---|---|
| 行 / カードアクション | アクションドロップダウン | role="menu" / role="menuitem" | ボトムアクションシート |
| ツールバーオーバーフロー("...") | オーバーフローメニュー | role="menu" / role="menuitem" | ボトムアクションシート |
| 右クリックキャンバスツール | コンテキストメニュー | role="menu" / role="menuitem" | 長押しボトムシート |
| フォームオプション選択 | コンボボックスセレクト | role="combobox" / role="option" | ネイティブセレクト / ボトムシート |
| マルチレベルビュー / フィルタートグル | チェック可能アクションパネル | role="menu" / role="menuitemcheckbox" | ボトムアクションシート |
配置と配置ルール
- データテーブル行メニュー: トリガーボタンに合わせて右上または右下に配置し、右のテーブルビューポート端を超える水平方向の切り捨てを防ぎます。
- ヘッダー / ナビゲーションアクション: 画面端への近さに応じて、右下または左下に配置します。
- サブメニュー: デフォルトで右に開きます(
left: 100%)。右側のスペースが200px未満の場合は、左に開くように反転します(right: 100%)。
制約
- アクセシビリティ(WCAG 2.1 AA):
- SC 1.4.3 コントラスト(最小): アイテムテキスト、アイコン、キーボードヒントは、メニュー背景に対して少なくとも 4.5:1 のコントラスト比を維持する必要があります。
- SC 2.1.1 キーボード: メニュー内のすべてのアイテムとアクションは、完全にキーボードでアクセス可能で、トリガー可能でなければなりません。
- SC 2.4.7 フォーカス可視: フォーカスされたメニューアイテムには、明確な視覚的フォーカス状態(例:背景色のシフト + コントラスト準拠のハイライトインジケーター)が必要です。
- SC 2.5.8 ターゲットサイズ: デスクトップメニューアイテムは少なくとも 32px の高さを維持する必要があります。モバイルアクションシートアイテムは、少なくとも 44x44px のタッチターゲットを満たす必要があります。
- ビューポート境界制約: 開いたメニューが画面外にはみ出したり、水平方向のページスクロールバーを作成したりしてはいけません。衝突反転と内部垂直スクロール(
max-height)を使用します。 - 空間パディングと密度: 一貫した内部水平パディング(例:
padding: 0.5rem 0.75rem)と垂直コンテナパディング(padding: 0.25rem 0)を維持します。
よくある失敗パターン
- フォームコンボボックスの混乱: フォームセレクトドロップダウンに
role="menu"を使用するが、role="combobox"/role="listbox"を使用すべきであり、スクリーンリーダーが値の選択とコマンドの実行を混同する原因となります。 - 閉じるときのフォーカス方向喪失:
Escapeキーまたは選択によってメニューが閉じたときに、フォーカスをトリガーボタンに戻せず、フォーカスがdocument.bodyで失われたままになる。 - クリッピングコンテナトラップ: ドロップダウンメニューを
overflow: hiddenを持つテーブルセルまたはコンテナ内に配置すると、開いたメニューが視覚的に切り取られます。 - 小さなモバイルタップターゲット: タッチスクリーン上で、24pxの小さなデスクトップドロップダウンアイテムを、タッチフレンドリーなボトムシートに変換せずにレンダリングする。
- 偶発的なサブメニュー消去: カスケードサブメニューに意図タイマー遅延がなく、マウスがサブアイテムに向かって斜めに移動するとサブメニューが閉じてしまいます。
検証基準
- メニューコンテナは適切なARIAセマンティクス(
role="menu"、role="menuitem"、role="separator")を利用しています。 - キーボードナビゲーションは、
ArrowDown、ArrowUp、Home、End、Escape、および文字タイプアヘッドを完全にサポートしています。 - メニューを閉じると(
Escapeまたはアイテムクリック経由)、プログラムによってフォーカスがトリガー要素に復元されます。 - ビューポート衝突ルールは、画面オーバーフローなしに長いメニューをきれいに反転またはスクロールします。
- レスポンシブブレークポイント(
< 768px)は、デスクトップドロップダウンポップオーバーをタッチフレンドリーなボトムアクションシートに変換します。 - アイテムテキスト、ショートカットヒント、フォーカスインジケーターの背景は、WCAG AAコントラスト(≥4.5:1)を満たしています。