キーボード操作の可視化
j / k で選択が動き、Enter で開く、? で一覧が出る。押したキーが右下に浮かんで消えるので、動画や説明会で「何を押したか」が伝わる。
プレビュー
クリック
操作クリック/タップで動きます。
仕様書
- 向く場面
- j/k で移動するメール・一覧アプリ
- ? で一覧を出す慣習の実装
- デモ動画で押したキーを見せたい場面
- 避ける場面
- 入力欄フォーカス中も単キーを効かせる
- キー表示を読み上げに乗せる
- 見た目の強調だけで選択を伝える
- 構成要素
- 一覧(listbox)
- 選択行
- キーの代わりボタン
- 押したキーの表示
- ショートカット一覧ダイアログ
- 状態の帯
- 持っている状態
- 通常
- フォーカス
- キーボード
j/k で選択を移動、Enter で開く、? で一覧(ダイアログ)、Esc で閉じて一覧へ戻る。入力欄にフォーカスがある間は無効
- 支援技術
role=listbox+option+aria-activedescendant で選択を伝える。キー表示は aria-hidden。一覧は role=dialog+aria-modal+aria-labelledby、開くと閉じるボタンへフォーカスし背後は inert
- 動き
キー表示は即時に出て 700ms 後に 400ms でフェード。reduced-motion で停止
デザインの要点
- 単キーのショートカットは入力欄にフォーカスがあるときは無効にする。文字を打つたびに画面が動くのは事故
- ? で一覧を出すのは Gmail・GitHub と同じ慣習。覚えなくても発見できる入口を1つ置く
- 選択の移動は aria-activedescendant で伝える。見た目の強調だけでは、読み上げには何も起きていない
- 押したキーの表示は aria-hidden にする。読み上げに「j」と割り込まれると邪魔なだけ
プロのサイトでの実例
実例は「型の使われ方」の観察であり、コード・ロゴの転載ではありません。サイト側の更新で見え方が変わることがあります。
コード(コピーして使えます)
<div class="kso-wrap">
<div class="kso-top">
<span class="kso-title">受信トレイ</span>
<span class="kso-hint" aria-hidden="true"><kbd>j</kbd><kbd>k</kbd> 移動 <kbd>Enter</kbd> 開く <kbd>?</kbd> 一覧</span>
</div>
<ul class="kso-list" id="kso-list" role="listbox" tabindex="0" aria-label="メール一覧" aria-activedescendant="kso-i1">
<li role="option" id="kso-i1" aria-selected="true"><span class="kso-from">山田 ゆい</span><span class="kso-subj">見積書の再送をお願いします</span></li>
<li role="option" id="kso-i2" aria-selected="false"><span class="kso-from">経理部</span><span class="kso-subj">9月分の経費精算は 10/5 まで</span></li>
<li role="option" id="kso-i3" aria-selected="false"><span class="kso-from">Aoi Analytics</span><span class="kso-subj">週次レポートが生成されました</span></li>
<li role="option" id="kso-i4" aria-selected="false"><span class="kso-from">佐藤 健</span><span class="kso-subj">Re: 展示会ブースの図面</span></li>
<li role="option" id="kso-i5" aria-selected="false"><span class="kso-from">総務</span><span class="kso-subj">オフィスの入館証を更新してください</span></li>
</ul>
<div class="kso-touch" role="group" aria-label="キーの代わり">
<button type="button" data-key="k">k ↑</button>
<button type="button" data-key="j">j ↓</button>
<button type="button" data-key="Enter">Enter</button>
<button type="button" data-key="?">?</button>
</div>
<div class="kso-keycap" id="kso-keycap" aria-hidden="true"></div>
<div class="kso-overlay" id="kso-overlay" role="dialog" aria-modal="true" aria-labelledby="kso-ov-title" hidden>
<h2 id="kso-ov-title">キーボードショートカット</h2>
<dl>
<dt><kbd>j</kbd></dt><dd>次のメール</dd>
<dt><kbd>k</kbd></dt><dd>前のメール</dd>
<dt><kbd>Enter</kbd></dt><dd>開く</dd>
<dt><kbd>?</kbd></dt><dd>この一覧</dd>
<dt><kbd>Esc</kbd></dt><dd>閉じる</dd>
</dl>
<button type="button" id="kso-close">閉じる</button>
</div>
<div class="kso-band"><span class="kso-tag">状態</span><span id="kso-msg">1/5 山田 ゆい「見積書の再送をお願いします」を選択</span></div>
</div>