メインコンテンツへスキップ

HTMLの「a要素」と「button要素」の違い

HTMLの「a要素」と「button要素」の違い:使い分け

ページネーションの実装時、「これはリンクにすべきか、ボタンにすべきか?」と疑問に思った。調べてみると、使い分けの基準は「見た目」ではなく「役割」にあることがわかった。

この記事では <a><button> の違いと、Next.js での正しい使い方を整理する。

1. <a>(アンカー要素):ナビゲーションのためのもの

<a> 要素の役割は、ユーザーを別の場所に導くこと(ナビゲーション)。

  • 主な用途

    • 別のウェブページやサイトへの移動
    • ページ内アンカー(特定のセクションへのジャンプ)
    • メール送信(mailto:)や電話発信(tel:
  • 必須属性

    • href: リンク先の指定に必須。これがないとアクセシビリティ上の問題が生じる。
  • アクセシビリティの注意点

    • 意味のあるテキスト: 「ここをクリック」ではなく「ご利用ガイドを見る」など、リンク先がわかる表現にする。
    • 新しいタブの明示: target="_blank" を使う場合は、ユーザーが驚かないよう「(別ウィンドウで開く)」といった注釈を添えるのが親切。
Caution

a要素の誤用:onclickイベント専用にするのはNG href="#"href="javascript:void(0)" と記述して、JavaScriptの実行ボタンとして使うのは避けましょう。これはアクセシビリティを損なうだけでなく、意図しない挙動(ページトップに戻るなど)の原因になります。その場合は <button> を使いましょう。

2. <button>(ボタン要素):アクションのためのもの

<button> 要素の役割は、その場で何らかの操作を実行すること(アクション)

  • 主な用途

    • フォームの送信(Submit)
    • ダイアログ(モーダル)の開閉
    • メニューの展開、コンテンツの切り替え
  • type属性の使い分け

    • type="submit": フォームデータを送信する(デフォルト値)。
    • type="button": JavaScriptと組み合わせて、汎用的な操作に使用する。
    • type="reset": 入力内容をリセットする。
Warning

type 属性を省略すると、デフォルトの type="submit" が適用される。<form> 内にある <button>type を書き忘れると、クリックするたびにフォームが送信されてページがリロードされるバグになる。アクション用に <button> を使う場合は必ず type="button" を明記する習慣をつけよう。

  • アクセシビリティの注意点
    • 名前(ラベル)の提供: アイコンのみのボタン(×ボタンなど)には、aria-label 等で「閉じる」といった名前を付与する。
    • 状態の伝達: 押し込まれた状態なら aria-pressed など、適切なARIA属性を検討する。

3. 比較まとめ:どちらを使うべき?

特徴<a> 要素<button> 要素
役割移動(Where)実行(What)
動作の例URLが変わる、ページ内を移動する送信する、開く、変更する
必須属性hreftype (推奨)
見た目テキスト装飾が一般的(CSSでボタン風にもできる)立体的なボタンが一般的(CSSでリンク風にもできる)

見た目と役割の分離

「見た目がボタンだから <button> を使う」のは間違い。

  • 見た目がボタンでも、役割が「ページ遷移」なら <a> を使う。
  • 見た目がリンク(青文字)でも、役割が「アクション」なら <button> を使う。

Next.jsを使用している場合、ページ間の遷移には next/link<Link> コンポーネントを使用する。

import Link from 'next/link';
 
// Next.jsでの推奨される遷移方法
<Link href="/about">会社概要</Link>;

<Link> は内部的に <a> 要素を生成し、クライアントサイドナビゲーション(高速な遷移)やプリフェッチ(データの先読み)を最適化してくれる。

Note

この挙動は Next.js 13 以降(Pages Router では 12.2 以降)の仕様だ。それ以前は <Link> の子要素として手動で <a> を記述する必要があった。現在のドキュメントは最新の App Router を前提にしている。

5. 実際に迷ったケース

ページネーションの「前へ」「次へ」

見た目はボタンのような矢印 UI だが、クリックすると /posts/page/2 のように URL が変わる。移動(ナビゲーション)が目的なので <a> が正解だ。

迷いどころは無効状態の扱いだ。最初のページでは「前へ」、最後のページでは「次へ」が押せない。このとき <button disabled> にするか <span> にするかで悩んだ。

<button> はアクションを実行する要素なので、アクションが存在しない「移動先がない状態」に <button disabled> を当てるのは意味的に不自然だ。では <span aria-hidden="true"> にすればよいかというと、これはアクセシビリティ上の問題があるaria-hidden="true" はスクリーンリーダーからその要素を完全に隠してしまうため、視覚ユーザーには「前へ」が見えているのに、スクリーンリーダーユーザーには「前へという機能が存在する」こと自体が伝わらなくなる。

推奨パターンは <a> を残したまま aria-disabled="true" を付与する方法だ。

<a href="/posts/page/1" aria-label="前のページ">‹</a>
 
<a aria-disabled="true" aria-label="前のページ(現在最初のページです)">‹</a>

<a> 要素として残すことで「ナビゲーション要素が存在する」という文脈は保たれ、aria-disabled="true" で「今は操作できない」という状態がスクリーンリーダーに伝わる。CSS の pointer-events: none と合わせてクリックを無効化する。

Note

href のない <a> はデフォルトでキーボードフォーカスが当たらない。Tab キーで辿れるようにしたい場合は tabindex="0" も追加する。

タグによる絞り込み

記事に付いているタグをクリックすると、そのタグの記事一覧に絞り込まれる。これを「フィルタリング」というアクションと捉えると <button> に見える。しかし実際には /tags/react のように URL が変わるので、ナビゲーションだ。<a> が正解になる。

Tip

「URL が変わるか?」を確認するのが最も確実な判断基準だ。URL が変わる → <a>、URL が変わらず画面の状態だけ変わる → <button> と覚えておくと迷いにくい。パスだけでなく ?sort=desc のようなクエリパラメータや #section のようなハッシュが変わるケースもナビゲーションの一種なので <a> が正解だ。

検索の「検索」ボタン

検索キーワードを入力して結果ページ(例: /search?q=keyword)へ遷移する場合、これは「フォームデータの送信」というアクションなので、<form><button type="submit"> を使うのが正しい。「URLが変わるなら <a>」という原則に縛られて、送信ボタンを無理やり <a> で実装するのは誤りだ。

一方で、入力欄などがなく単に「検索専用ページはこちら」という固定URLへのリンクを設置したい場合は、ナビゲーションなので <a href="/search"> を使うべきだ。「見た目をボタンにしたいから」という理由で、<button onclick="location.href='/search'"> のようにJavaScriptでページ遷移させるのはアクセシビリティを損なうため避けるべきだ。

なお、テキスト入力のたびに画面遷移なしでリアルタイム絞り込みを行うような実装(インクリメンタルサーチ)では、フォーム送信をJavaScriptで制御しつつ、入力イベントに応じた非同期処理(API通信など)を行う形になる。

6. 結論:ページネーションはどうすべき?

調査の結果、今回の疑問への答えはこうなった。

「ページネーションは、基本的には <a> 要素(Next.jsなら <Link>)を使うのがベスト」

なぜなら、ページネーションは「URLを変更して、そのページの内容を表示する」というナビゲーション(移動)の性質が強いから。検索エンジン(SEO)もリンクを辿って各ページをクロールするため、<a> 要素を使うことが推奨される。

まとめ

  • <a>移動(ナビゲーション)<button> は**実行(アクション)**が役割の違い
  • 見た目でどちらを使うかを決めるのは誤り。CSS でどちらの見た目にもできる
  • 「URL が変わるか?」 が最も確実な判断基準。変わる → <a>、変わらない → <button>
  • ページネーション・タグ絞り込みは URL が変わるのでどちらも <a>(Next.js なら <Link>)が正解
  • 無効状態は aria-hidden で隠すのではなく <a aria-disabled="true"> でスクリーンリーダーにも状態を伝える
  • <button>type 省略は type="submit" 扱いになるため、アクション用には type="button" を必ず明記する
  • Next.js でのページ遷移は <Link> を使うことで、クライアントサイドナビゲーションが最適化される

<a><button> の使い分けを意識するだけで、アクセシビリティと SEO の両方が改善される。HTML を書くときに「これは移動か?それともアクションか?」と一度立ち止まる習慣をつけてみてほしい。

参考