「検索ボックスにキーボードだけで一発で移動したい」「送信ボタンをキー操作で押せるようにしたい」。そんなときに使えるのが HTML の accesskey 属性です。JavaScript を書かなくても、要素に1文字割り当てるだけでキーボードショートカットが作れます。この記事では、accesskey の書き方と値のルール、ブラウザーと OS で異なる押し方、要素によって動作が変わる仕組み、そして「便利そうに見えて実は扱いが難しい」と言われる理由と、それでも使うときの原則までを解説します。
目次
accesskey 属性でできること
accesskey は、その要素を呼び出すためのキーボードショートカットを指定するグローバル属性です。グローバル属性なので <button> や <a> だけでなく、<div> や <p> を含むあらゆる HTML 要素に付けられます。
<!-- 「s」がこのボタンのアクセスキーになる --> <button type="submit" accesskey="s">送信する</button> <!-- リンクにも付けられる --> <a href="/" accesskey="h">ホームへ</a> <!-- 入力欄にフォーカスを移すショートカット --> <input type="search" name="q" accesskey="4">
これだけで、指定したキーと修飾キーの組み合わせを押したときに、その要素にフォーカスが移ったり、クリックされたのと同じ動作が起きたりします。JavaScript は一切不要です。ただし「どのキーと一緒に押すのか」がブラウザーと OS でばらばらだ、という大きな癖があります。まずはそこから見ていきましょう。
押すキーはブラウザーと OS で違う
accesskey に書いた文字を単独で押しても何も起きません。実際には修飾キーと組み合わせて押しますが、その組み合わせは HTML 側では決められず、ブラウザーと OS が決めています。主要なブラウザーでの組み合わせは次のとおりです。
| ブラウザー | Windows / Linux | macOS |
|---|---|---|
| Chrome | Alt + キー | Control + Option + キー |
| Edge | Alt + キー | Control + Option + キー |
| Firefox | Alt + Shift + キー | Control + Option + キー |
| Safari | (対象外) | Control + Option + キー |
macOS はどのブラウザーでも Control + Option で統一されている一方、Windows では Firefox だけ Shift が加わります。つまり「Alt + S で送信できます」と画面に書いても、Firefox のユーザーには当てはまりません。案内を書くときは、ブラウザーによって押し方が違うことも一緒に伝えるか、修飾キーには触れずキーだけを示すのが無難です。
なお、これはブラウザーの実装であって仕様で決まっているものではないため、バージョンによって変わる可能性があります。実際に配布する前に、想定する環境で必ず動作を確かめてください。
値は1文字、候補を複数並べることもできる
accesskey の値は印字可能な1文字です。accesskey="save" のように単語を書くことはできません。ただし、半角スペース区切りで複数の候補を並べることはできます。この場合、ブラウザーはその中から自分の環境で使えるものを1つ選びます。
<!-- 1文字だけ指定する(基本) --> <button accesskey="s">保存</button> <!-- 候補を複数並べる。使えるものをブラウザーが1つ選ぶ --> <button accesskey="s 1 ん">保存</button> <!-- これは無効:値は1文字でなければならない --> <button accesskey="save">保存</button>
複数候補が用意されているのは、キーボードの配列が国や地域によって違うためです。ある文字が特定の配列のキーボードに存在しないことがあるので、代替を並べておけば、その環境でも何らかのキーが割り当てられます。逆に言えば、どのキーが選ばれたかは実行時までわからないということでもあります。
この点を踏まえると、実務では英字よりも数字を割り当てるほうが安全な場面が多くなります。数字はどの配列のキーボードにもあり、ブラウザー自身のショートカット(Windows でのタブ切り替えなど)とぶつかることはあっても、文字キーほど衝突の種類が多くないためです。
フォーカスするだけの要素と、クリックされる要素
アクセスキーを押したときの動作は、要素の種類によって2種類に分かれます。ボタンやリンク、チェックボックスのように押されたときの動作が決まっている要素は、クリックされたのと同じように動きます。リンクならページが移動し、チェックボックスならチェックが切り替わり、ボタンなら click イベントが発生します。
一方、テキスト入力欄や <textarea> のように押しても実行する動作がない要素では、単にフォーカスが移動するだけです。「検索欄に一瞬で移動する」といった使い方はこちらにあたります。実際に手を動かして確かめてみましょう。次のデモは、入力欄・チェックボックス・ボタン・リンクにそれぞれアクセスキーを割り当てたものです。
<div class="demo">
<p class="hint">
プレビュー内をクリックしてから、
<kbd>Alt</kbd>(Windows)/<kbd>Control</kbd>+<kbd>Option</kbd>(macOS)と各キーを一緒に押してみてください。
</p>
<!-- テキスト入力:フォーカスが移動する -->
<label class="row" for="keyword">
<span class="name">キーワード</span>
<kbd>S</kbd>
<input id="keyword" type="text" accesskey="s" placeholder="ここにフォーカスが移動します">
</label>
<!-- チェックボックス:クリックされたのと同じ扱いになる -->
<label class="row">
<span class="name">お知らせを受け取る</span>
<kbd>C</kbd>
<input type="checkbox" accesskey="c">
</label>
<div class="row">
<!-- ボタン:押されたのと同じ扱いになる -->
<button type="button" accesskey="b" onclick="this.textContent = '押されました'">送信する</button>
<kbd>B</kbd>
<!-- リンク:たどられる(ページ内リンク) -->
<a href="#target" accesskey="h">下の説明へ</a>
<kbd>H</kbd>
</div>
<p id="target" class="target">ここがリンク先です。フォーカスの枠線が動くかどうかも確認してみてください。</p>
</div>
body {
font-family: system-ui, sans-serif;
margin: 0;
padding: 16px;
color: #333;
}
.demo {
max-width: 480px;
}
.hint {
margin: 0 0 16px;
font-size: 13px;
line-height: 1.7;
color: #555;
}
.row {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
}
.name {
font-size: 14px;
white-space: nowrap;
}
/* 押すキーを画面上にも表示しておく */
kbd {
display: inline-block;
min-width: 18px;
padding: 2px 6px;
border: 1px solid #bbb;
border-bottom-width: 2px;
border-radius: 4px;
background: #f7f7f7;
font-family: inherit;
font-size: 12px;
text-align: center;
color: #444;
}
input[type="text"] {
flex: 1;
padding: 6px 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
}
button {
padding: 6px 14px;
border: 1px solid #007bff;
border-radius: 4px;
background: #007bff;
color: #fff;
font-size: 14px;
cursor: pointer;
}
a {
color: #007bff;
font-size: 14px;
}
/* アクセスキーでフォーカスが移ったことが分かるようにする */
input:focus,
button:focus,
a:focus {
outline: 3px solid #ffb400;
outline-offset: 2px;
}
.target {
margin: 20px 0 0;
padding: 10px 12px;
border-left: 4px solid #ddd;
background: #fafafa;
font-size: 13px;
line-height: 1.7;
}
プレビュー内を一度クリックしてフォーカスを移してから、先ほどの表の組み合わせで S・C・B・H を押してみてください。S では入力欄に枠線が付くだけですが、C ではチェックが切り替わり、B ではボタンのラベルが変わります。同じ属性でも、要素によって結果が違うことがわかります。
なお、<div> や <p> のような、そのままではフォーカスを受け取れない要素にアクセスキーを付けた場合、フォーカスが移るかどうかはブラウザーによって挙動が分かれます。確実にフォーカスさせたいときは tabindex="-1" を併せて指定し、その要素がフォーカス可能であることを明示してください。
割り当てたキーを画面に表示する(accessKeyLabel)
アクセスキーの最大の弱点は、ユーザーがその存在に気づけないことです。ソースを読まない限り、どのキーで何ができるのかはわかりません。ですから、使うのであれば画面上に明示するのが前提になります。もっとも確実なのは、次のように自分で書いてしまう方法です。
<button type="submit" accesskey="s"> 送信する <kbd>S</kbd> </button>
DOM 側には accessKeyLabel という読み取り専用プロパティがあり、その要素に割り当てられたアクセスキーを、修飾キーを含めた表示用の文字列として返してくれます。ブラウザーごとの押し方の違いを自動で反映した文字列が得られるので、理屈のうえでは理想的な方法です。
const button = document.querySelector('button[accesskey]');
// 実装しているブラウザーでは "Alt+S" のような文字列が入る
if (button.accessKeyLabel) {
button.textContent = `送信する (${button.accessKeyLabel})`;
}
ただし accessKeyLabel を実装しているのは Firefox だけで、Chrome・Edge・Safari では空文字列が返ります。上のコードのように値があるときだけ使うぶんには害はありませんが、これに頼って表示を組み立てることはできません。実際には、押すキーの文字だけを自分でマークアップに書いておき、修飾キーの説明はヘルプやページ内の案内でまとめて示す、という形が現実的です。
なお、割り当てた文字そのものを取得したいだけなら、element.accessKey で属性値を読み書きできます。こちらは各ブラウザーで利用できます。
ショートカットが効かないとき
ブラウザーや OS のショートカットに取られている
もっとも多い原因がこれです。Alt + 英字の組み合わせは、ブラウザー自身のメニュー呼び出しや OS の機能に多数割り当てられています。ページ側のアクセスキーが優先されるか、ブラウザーの機能が優先されるかは実装次第で、後者になれば当然ページの要素は反応しません。
特にファイル・編集・表示といったメニューの頭文字や、よく使われる F・D・N・T・W などは避けたほうが安全です。数字を使う、あるいは先ほどの複数候補の書き方で逃げ道を用意しておくと、衝突の影響を減らせます。
スクリーンリーダーが同じキーを使っている
スクリーンリーダーは、見出し送りや表の読み上げなどに多数のキーボードショートカットを割り当てています。支援技術を使っているユーザーにとっては、そちらのショートカットが使えなくなるほうが深刻な問題です。「キーボード操作の人のために付けた属性が、かえってキーボード操作の人の邪魔をする」という逆転が起こりやすいのが、この属性の難しいところです。
要素が無効・非表示になっている
disabled が付いたフォーム部品や、display: none や hidden 属性で隠された要素は操作の対象になりません。条件によってボタンを無効化している画面で「ときどきショートカットが効かない」という場合は、まずその時点の要素の状態を確認してください。JavaScript で後から accesskey 属性を追加した場合も、その要素が画面に存在していなければ当然反応しません。
キーボード配列に文字が存在しない
先ほど触れたとおり、指定した文字がユーザーのキーボード配列に無ければ、そのアクセスキーは使えません。日本語環境では日本語キーボードと英語キーボードで記号の位置が違うので、記号を割り当てるのは特に避けるべきです。英字か数字にとどめておきましょう。
アクセシビリティの観点から見た注意点
ここまで見てきたとおり、accesskey は仕様としては単純ですが、実際の環境では扱いにくい属性です。MDN のドキュメントでも、既存のショートカットとの衝突、キーボード配列による利用可否、ユーザーに知らせる手段が無いことなどを理由に、使用には注意が必要であるとされています。アクセシビリティを高める目的で導入したつもりが、かえって使いにくくしてしまう可能性があるわけです。
関連して、WCAG 2.1 には「2.1.4 文字キーのショートカット」という達成基準があります。これは修飾キーを伴わない1文字のショートカットを実装する場合に、無効化する手段・キーの再割り当て・フォーカス時のみ有効にする、のいずれかを提供することを求めるものです。accesskey は通常 Alt などの修飾キーと組み合わせて押すため、この基準がそのまま当てはまるわけではありませんが、「ユーザーの既存のキー操作を奪わない」という考え方は共通しています。
それでも使う場面はあります。社内システムや管理画面のように、利用環境とユーザーがある程度限定されていて、繰り返しの入力作業を速くしたい場合です。その際は、割り当てるのは検索・保存・新規作成といった本当に頻繁に使う数個だけに絞り、押すキーを画面上に明示し、対応環境を案内する、という三点を守ってください。ページ内の全リンクに機械的に付けるような使い方は避けましょう。
ちなみに、ページ先頭に「本文へスキップ」のリンクを置くスキップリンクは、キーボード利用者の移動を助ける手段として広く定着しており、アクセスキーのような衝突の問題がありません。ナビゲーションを飛ばしたいだけであれば、まずこちらを検討するとよいでしょう。
JavaScript で独自のショートカットを作る
修飾キーの組み合わせを自分で決めたい、ショートカットの一覧をユーザーに設定させたい、といった要件があるなら、keydown イベントで実装するほうが自由に作れます。accesskey と違って、押すキーも修飾キーもこちらで完全に決められます。
document.addEventListener('keydown', (event) => {
// 入力中は発動させない
const tag = event.target.tagName;
if (tag === 'INPUT' || tag === 'TEXTAREA' || event.target.isContentEditable) {
return;
}
// Ctrl(macOS では Command)+ K で検索欄にフォーカス
if ((event.ctrlKey || event.metaKey) && event.key === 'k') {
event.preventDefault(); // ブラウザー既定の動作を止める
document.querySelector('#search').focus();
}
});
押されたキーは event.key で、修飾キーの状態は ctrlKey・metaKey・altKey・shiftKey で判定します。event.preventDefault() を呼ばないとブラウザー既定の動作も同時に実行されてしまうので、上書きするつもりのショートカットでは忘れずに呼んでください。
自由度が高い代わりに、衝突を避ける責任もすべて自分側に移ります。ブラウザーの重要なショートカットを潰していないか、テキスト入力中に誤発動しないか、そしてショートカットの一覧をユーザーが確認できるかを、必ず設計に含めてください。
まとめ
accesskey は、任意の HTML 要素にキーボードショートカットを割り当てられるグローバル属性です。値は印字可能な1文字で、半角スペース区切りで複数の候補を並べるとブラウザーが使えるものを選びます。押すときの修飾キーはブラウザーと OS で異なり、Windows の Chrome・Edge は Alt、Firefox は Alt + Shift、macOS はいずれも Control + Option です。動作はボタンやリンク、チェックボックスならクリック相当、テキスト入力欄ならフォーカスの移動になります。割り当てたキーを表示用の文字列で取得できる accessKeyLabel は Firefox だけの実装なので、押すキーは自分でマークアップに書いておくのが確実です。ブラウザーや支援技術のショートカットと衝突しやすく、ユーザーに存在を気づいてもらいにくい属性でもあるため、使うなら本当に頻度の高い数個に絞り、画面上に明示することが欠かせません。より柔軟な制御が必要なら、keydown イベントによる実装も検討してみてください。