HTML でボタンを作る方法
ボタンは <button> 要素です。タグの間の内容がユーザーに見える部分で、type="button" はフォームを送信するのではなく自分のスクリプトを実行するボタンだという意味です。プレビューでクリックしてみてください。
動くボタンに必要なのはこれだけです。ラベル、type、そして click を受け取る処理です。ブラウザはボタンをキーボードでフォーカスできるようにし、Enter キーやスペースキーで押せるようにするので、キーボードのユーザーは何もしなくても使えます。クリック処理を付けた <div> にはそのどれもありません。
タグの中に onclick="..." を直接書いた例を見かけることもあります。これでも動きますが、addEventListener ならスクリプトをマークアップから切り離せ、1 つのボタンに複数のリスナーを付けられます。
ボタンの 3 つの type
押したときにボタンが何をするかは type 属性で決まります。
type | 動作 | 用途 |
|---|---|---|
submit | 自分が属するフォームを送信する。これが初期値 | フォームのメインの操作 |
button | それ自体は何もせず、JavaScript が動作を決める | 切り替え、ダイアログ、カウンターなどスクリプトで動くもの |
reset | フォームのすべての入力欄を初期値に戻す | めったに使わない。ユーザーが間違えて押しやすい |
何か入力してから、各ボタンを試してみてください。プレビューはフォームを送信してもページを移動せず、フォームが送るはずだったデータを表示します。
Reset は空の入力欄ではなく、HTML に書かれた値 (Ada) に戻します。また、Uppercase から type="button" を消すと送信ボタンになり、名前を大文字にした後でフォームを送信します。
HTML の送信ボタン: name と value を送る
送信ボタンは自分の name と value を持てます。これらはそのボタンでフォームが送信されたときにだけ一緒に送られるので、1 つのフォームに 2 つのボタンを置いて、どちらの操作が選ばれたかをサーバーに伝えられます。
Publish を押すと、フォームは title=My first post と action=publish を送ります。タイトルを空にしてどちらかのボタンを押すと、required が送信を止め、ブラウザが独自のメッセージを表示します。テキスト欄の中で Enter キーを押しても送信され、ブラウザはそれを最初の送信ボタンが押されたものとして扱うので、action=draft が送られます。
送信ボタンには、そのボタンに限ってフォームの設定を上書きする属性もあります。formaction (別の URL)、formmethod、formtarget、そして入力チェックを飛ばす formnovalidate です。必須の入力欄がまだ空でも動いてほしい「下書き保存」ボタンには、普通 formnovalidate を使います。
フォームの外に置いたボタンでも、フォームの id を指定する form 属性を使えばそのフォームを送信できます: <button type="submit" form="signup">Sign up</button>。
無効なボタン
disabled 属性でボタンを無効にできます。無効なボタンはクリックを無視し、Tab キーでは飛ばされ、フォームと一緒に送信されません。ブラウザはグレーで表示します。条件が満たされるまで送信ボタンを無効にしておくのはよくあるパターンです。
JavaScript では button.disabled は真偽値のプロパティなので、true か false を設定します。HTML では属性があるかどうかで決まるので、disabled="false" と書いてもボタンは無効になります。
無効なボタンは、なぜ無効なのかを教えてくれません。また、Tab キーで移動するキーボードやスクリーンリーダーのユーザーはそのボタンにたどり着きません。理由が明らかでないときは、ボタンの横にテキストで書くか、ボタンを有効のままにして押したときにエラーメッセージを表示しましょう。
CSS でボタンをデザインする
ブラウザは独自のフォント、枠線、背景でボタンを描きます。いくつかのプロパティを指定すれば、それをすべて置き換えられます。フォーカスのスタイルは見えるように残しましょう。キーボードのユーザーはそれで現在の位置を知ります。
各ルールの役割です。
font: inheritで、ボタンにページのフォントを使わせます。これがないと、ボタンはブラウザ独自の小さなフォームのフォント (Chrome と Firefox では 13.33px) になります。cursor: pointerで手の形のカーソルを表示します。ボタンは初期状態では普通の矢印です。:hover、:active、:focus-visibleで、ポインター、押下、キーボードの各状態にスタイルを付けます。:focus-visibleはキーボードでのフォーカスにはリングを表示し、マウスでクリックした後には表示しないので、リングを消すためにoutlineを外す必要はありません。:disabledはdisabled属性の付いたボタンを対象にします。
プレビューで Tab キーを押すと、琥珀色のフォーカスリングが最初の 2 つのボタンの間を移動します。無効なボタンは飛ばされます。(Mac の Safari と Firefox では、システム設定でキーボードナビゲーションをオンにしたときだけ Tab キーでボタンに移動します。Safari では、オンにしなくても Option+Tab で移動できます。) 状態の一覧は CSS の hover を参照してください。
アイコン付きのボタン
<button> には HTML を入れられるので、アイコンはテキストの横、ボタンの中に置きます。アイコンだけのボタンにはスクリーンリーダーが読み上げるテキストがないので、aria-label を付けましょう。
SVG に付けた aria-hidden="true" で SVG をアクセシビリティツリーから外しているので、1 つ目のボタンは「Add item、ボタン」、2 つ目は「Delete、ボタン」と読み上げられます。
button と input type="submit" の違い
<input type="submit"> は送信ボタンの古い書き方です。どちらも同じようにフォームを送信し、違いは中に入れられるものです。
<input type="submit" value="Send"> <!-- label comes from value, text only -->
<button type="submit">Send</button> <!-- label is the content, HTML allowed -->
<button> | <input type="submit"> | |
|---|---|---|
| ラベル | タグの間の内容 | value 属性 |
| アイコンやマークアップを入れられるか | はい | いいえ |
| 終了タグ | 必要 | なし (空要素) |
| type の初期値 | submit | 常に送信 |
<button> を使いましょう。<input type="submit"> を残す理由は、それを選択している既存の CSS や JavaScript があることくらいです。ほかの 2 つの type に対応する <input type="button"> と <input type="reset"> もあります。
ボタンかリンクか
ボタンは現在のページで何かを実行します。送信する、開く、切り替える、削除する、などです。リンクは別の URL に移動します。クリックでアドレスバーが変わるなら <a href> にして、デザイン上必要ならボタンの見た目にしましょう。そのパターンと、リンクの中のボタンが無効になる理由は HTML のボタンリンク で解説しています。
アクセシビリティ
- 本物の
<button>を使いましょう。フォーカスでき、Enter キーとスペースキーで動き、ボタンとして読み上げられます。<div>でそれを作り直すにはrole、tabindex、キー操作の処理が必要で、それでもたいてい不完全です。 - どのボタンにも名前が必要です。テキスト、またはアイコンだけなら
aria-labelです。 - フォーカスのスタイルは見えるように残しましょう。代わりを用意せずに
outline: noneにすると、キーボードのユーザーは迷ってしまいます。 - 押しやすい大きさにしましょう。WCAG 2.2 は最低でも 24 × 24 CSS ピクセルを求めています。上のデザイン例のような padding なら、高さは約 40 ピクセルになります。
- 切り替えボタンには
aria-pressed="true"または"false"を付け、状態が変わったら更新します。
よくある間違い
- フォームの中で
typeのないボタンを使う。 フォームが送信されます。送信用でないボタンにはすべてtype="button"と書きましょう。 - ボタンをリンクで囲む。
<a href="/x"><button>Go</button></a>は無効な HTML で、ブラウザによって動作が変わります。ボタンの見た目にしたリンク 1 つにしましょう。 - ボタンとして
<div onclick>を使う。 キーボードで操作できません。 :focus-visibleのスタイルを追加せずにフォーカスの outline を消す。disabled="false"と書いて、ボタンが有効になると思う。 属性ごと外しましょう。font: inheritを忘れる。 ボタンだけページのほかの部分と違うフォントになります。
よくある質問
HTML でボタンを作るにはどうすればいいですか?
<button type="button">Click me</button> と書きます。タグの間のテキストがボタンのラベルです。何かを実行させるには JavaScript で click リスナーを追加し、フォームを送信させるには type="submit" を付けて <form> の中に置きます。
HTML の button の type の初期値は何ですか?
submit です。フォームの中にある type 属性のない <button> は、クリックするとそのフォームを送信します。フォーム内の普通のボタンでページが再読み込みされることがあるのはこのためです。JavaScript を実行するボタンには type="button" と書きましょう。
button と input type=submit の違いは何ですか?
どちらもフォームを送信します。<button> はタグの間に HTML (アイコンや太字のテキスト) を入れられますが、<input type="submit"> はラベルを value 属性から取り、普通のテキストしか持てません。最近のコードではほとんど <button> を使います。
HTML でボタンを無効にするには?
disabled 属性を付けます: <button disabled>Save</button>。無効なボタンはクリックもフォーカスもできず、name と value はフォームと一緒に送信されません。属性を外す (JavaScript では btn.disabled = false) と再び有効になります。
HTML のボタンで別のページに移動するには?
ボタンの見た目にしたリンクを使います: <a href="/pricing" class="btn">See pricing</a>。<button> は現在のページで何かを実行するためのものです。ボタンを <a> で囲むのは無効な HTML です。
ボタンを押すとページが再読み込みされるのはなぜですか?
<form> の中にあって type がないので送信ボタンになっており、ブラウザがフォームを送信してレスポンスを読み込んでいます。ボタンに type="button" を付けるか、フォームを JavaScript で処理するなら submit リスナーの中で event.preventDefault() を呼びましょう。