Webサイトのコードを読み込んでいる際や、既存サイトのリファクタリングを行っている時に、href="javascript:void(0)"という記述を見かけたことはないでしょうか。「なんとなくページ遷移を防ぐためのおまじない」として使われがちですが、その正確な意味やブラウザ内部での動作を理解している人は意外と多くありません。
さらに、現代のWebフロントエンド開発において、javascript:void(0)を疑似ボタンとして使用することは「非推奨(アンチパターン)」とされています。単に「古い書き方だから」という理由だけでなく、アクセシビリティ(支援技術への対応)の低下や、検索エンジンクローラーへの影響、HTMLセマンティクスの違反といった明確な技術的理由が存在するためです。
それでは、既存コードのjavascript:void(0)を見つけた場合、私たちは一体どのように修正・実装を行うべきなのでしょうか?
本記事では、JavaScript・HTML・アクセシビリティ・SEOの技術的な仕様に基づき、以下のポイントを分かりやすく解説します。
結論として、操作を実行したい場合はセマンティックな<button type="button">を選択し、リンクの既定動作を制御したい場合はevent.preventDefault()を使用するのが現代のWeb標準における正解です。この記事を通じてjavascript:void(0)の仕組みを深く理解し、実務で使える高品質で保守性の高いコードへアップデートしていきましょう。
javascript:void(0) の意味とは?void 演算子の仕組みと役割

Web制作やフロントエンド開発の現場で、アンカータグ(<a>要素)のhref属性に指定されたjavascript:void(0)という記述を見かけたことがある方は多いでしょう。
この記述は、リンクをクリックした際にページが遷移したり再読み込みされたりするのを防ぐ目的で、長年にわたり広く使われてきました。しかし、その裏でどのような処理が行われているのか、なぜこの書き方が選ばれてきたのかを正確に理解している方は案外少ないかもしれません。
javascript:void(0)を構成するJavaScriptのvoid演算子の仕組みから、ブラウザ内部での動作、そして歴史的背景までを技術的な視点から紐解いていきます。
void(0)がundefinedを返す理由と仕組み
JavaScriptのvoid演算子は、指定した式を評価した上で、その結果にかかわらず常に原始値(プリミティブ型)の undefined を返す演算子です。
構文としては、void expression のようにスペースを空けて記述することも、関数のように void(expression) のように括弧で囲んで記述することも可能です。どちらの書き方であっても挙動に違いはありません。
次のコード例を見てみましょう。
console.log(void 0); // undefined
console.log(void(0)); // undefined
console.log(void(1 + 2)); // undefined
void 演算子は、右側に記述された式(上記の例では 0 や 1 + 2)を通常通り評価します。しかし、評価が完了したあとに、その値が何であっても強制的に undefined に置き換えて返却するという性質を持っています。
JavaScriptにおいて、グローバルスコープの undefined は書き換え可能な変数として扱われてきた歴史的経緯があります(古い仕様では変更可能でした)。そのため、確実に純粋な undefined というプリミティブ値を得るための安全な手段として、void 0 や void(0) というイディオムが利用されてきました。
詳しい仕様については、MDN Web Docsのvoid 演算子も併せて参考にしてください。
なぜaタグのhrefにjavascript:void(0)が使われてきたのか(歴史的背景)
では、なぜ単なる値の評価にすぎない void(0) が、HTMLの <a> タグの href 属性で使われてきたのでしょうか。その理由は、javascript: という疑似プロトコルとブラウザの挙動にあります。
HTMLの <a> 要素は、本来であれば別のページやファイル、あるいは同一ページ内のアンカーへ遷移するためのナビゲーションを担う要素です。そのため、href 属性が省略されていたり、単なる空文字やハッシュ(#)が指定されていたりすると、予期せぬページトップへのスクロールや不要な読み込みが発生することがありました。
そこで、クリック時に画面を遷移させず、かつJavaScriptの処理だけを実行させたいという目的で、次のような手法が考案されました。
<!-- リンクとしての遷移を防ぎつつ、クリックイベントを発火させたい場合の古い実装例 -->
<a href="javascript:void(0);" onclick="handleClick()">クリック</a>
ブラウザは javascript: で始まるURLを検知すると、その後に続くJavaScriptコードを実行し、その評価結果(返り値)を画面にレンダリングしようと試みます。もし返り値が文字列などであれば、ブラウザはその文字列でページを丸ごと上書きしてしまいます。
ここで void(0) が役立ちます。void(0) の評価結果は常に undefined であるため、ブラウザは「何も新しいコンテンツを出力しない(ページ遷移を行わない)」と判断します。これにより、見た目はリンクでありながら、クリックしても画面が動かない「疑似ボタン」を実現することができました。
しかし、この手法はあくまで当時のブラウザ仕様とハック的なアプローチを組み合わせたものであり、現在のWeb標準が目指すセマンティックな設計やアクセシビリティの観点からは、多くの課題を抱える実装方法となっています。
void(0)/void(1)/void(null)による挙動の違い
先述の通り、void 演算子はどのような式を渡しても最終的な返り値として undefined を返します。そのため、実用上は void(0) も void(1) も、あるいは void(null) であっても、返り値という観点では違いがありません。
しかし、JavaScriptの言語仕様や式の評価という観点では、内部的な処理に明確な違いが存在します。
// いずれも返り値は「undefined」になる
const result1 = void(0);
const result2 = void(1);
const result3 = void(null);
console.log(result1 === result2); // true (すべて undefined)
この違いを理解する上で重要なのが、「式の評価」と「副作用」です。
void 演算子の右側に置かれた式は、必ず評価(実行)されます。例えば、次のような関数呼び出しを伴う式を渡した場合は注意が必要です。
function doSomething(){
console.log("関数が実行されました");
return 100;
}
// void をつけても関数自体は実行される
const val = void(doSomething());
console.log(val); // 最終的な返り値は undefined だが、コンソールには「関数が実行されました」と出力される
このように、void(0) の 0 や void(1) の 1 は単純なリテラルであるため副作用はありませんが、より複雑な式を渡した場合は、返り値が undefined になるからといって、式内部の処理が行われないわけではありません。
実務においては、コードの意図を明確にし、余計な誤解を生まないためにも、特別な理由がない限りは最もシンプルで慣習的に使われている void(0) または void 0 を使用するのが一般的です。
なぜjavascript:void(0)は非推奨とされるのか?3つの技術的理由

かつて多くのWebサイトで重宝されてきた javascript:void(0) ですが、現在のWeb標準やアクセシビリティ、そしてSEOの観点からは、積極的に避けるべきアンチパターンとされています。
その理由は、単に「古い書き方だから」というものではなく、ブラウザの挙動、支援技術の利用体験、そして検索エンジンのクロール性能に実質的な悪影響を及ぼすためです。
このセクションでは、javascript:void(0) が非推奨とされる3つの技術的理由を詳しく解説します。
アクセシビリティの低下(スクリーンリーダー・キーボード操作への支障)
もっとも大きな課題の一つが、アクセシビリティ(Web A11y)の著しい低下です。
HTMLの <a> 要素は、ブラウザやスクリーンリーダーなどの支援技術に対して「ここをクリックすると別のページやリソースへ移動する(ナビゲーション)」という明確なセマンティック(意味論的)情報を伝えます。しかし、実態としてページ遷移を行わず、モーダルの開閉やタブの切り替えといった「画面内の状態変更(アクション)」を目的として javascript:void(0) を使用した場合、支援技術を利用しているユーザーに大きな混乱を与えます。
- スクリーンリーダーの誤認:
スクリーンリーダーは<a>要素を読み上げる際に「リンク」としてアナウンスします。ユーザーは「別のページに移動する」と期待してクリックするものの、実際にはページ内の一部が変化するだけであり、期待されたナビゲーションが起きないため操作性が損なわれます。 - キーボード操作やフォーカスの仕様差異:
<button>要素であればEnterキーやSpaceキーの押下によって標準でクリックイベントが発火しますが、<a>要素を疑似ボタンとして扱う場合、キーボード操作のハンドリングを独自に実装しなければならないケースが生じます。 - JavaScript依存による機能不全:
JavaScriptが無効化されている環境や、スクリプトの読み込みエラーが発生した際、href="javascript:void(0)"が指定されたリンクは文字通り「何も起きない死んだリンク」となり、ユーザーが代替手段を得られなくなります。
本来、操作を実行するトリガーには、セマンティックな <button> 要素を選択すべきです。
SEO・クローラーへの悪影響(内部リンク構造の正当な評価阻害)
SEOの観点においても、javascript:void(0) の多用は推奨されません。
Google検索セントラルの「リンクに関するベストプラクティス」公式ドキュメントでは、検索エンジンがページを効率的にクロールし、サイト構造やリンクジュース(PageRank)を正しく伝達するために、<a> タグには有効なURL(href 属性)が設定されている必要があることが示されています。
- クローラーによるリンクの追跡阻害:
Googleなどの検索エンジンクローラーは、href属性に記述されたURLをたどってサイト内を巡回します。ここにjavascript:void(0)や#が指定されていると、クローラーはそこを「有効なリンク先がない(あるいは移動先が不明な)場所」と判断します。 - サイト構造の評価低下:
本来は重要なページへ誘導すべき内部リンクにこの記述が使われていると、検索エンジンがサイト内の階層構造やページ間の関連性を正しく読み取れず、インデックス効率や評価に悪影響を及ぼす可能性があります。
なお、「javascript:void(0) を使った瞬間に直接ペナルティを受ける」といった過激な言説は誤りですが、「クローラーが本来たどるべき有用なリンクを失わせ、サイト全体の評価伝達を妨げる」という点で、SEO上の大きなデメリットとなります。
プログレッシブ・エンハンスメントおよびセマンティックHTMLの原則違反
現代のWeb開発の根底にある設計思想が、「プログレッシブ・エンハンスメント(段階的拡張)」と「セマンティックHTML」です。
HTMLは「文書の構造と意味」を定義し、CSSは「見た目や装飾」を担い、JavaScriptは「振る舞いやインタラクション」を付加するという役割分担(関心の分離)が基本原則となります。
- 責務の混同:
<a>要素は「文書間の移動(ナビゲーション)」のために存在し、クリック時のJavaScriptによる挙動はあくまで補助的な拡張(プログレッシブ・エンハンスメント)であるべきです。最初からJavaScriptの実行を前提として<a>をボタン代わりに使う設計は、この構造的な原則に反しています。 - 保守性と再利用性の低下:
構造と動作が強く結びついたコードは、後からリファクタリングを行う際や、別のフレームワークへ移行する際に障害となりやすいほか、コードの意図を他の開発者が読み解くコストを高める原因にもなります。
レイアウトの都合や「リンクっぽいデザインにしたい」という理由だけで <a> タグを流用するのではなく、目的に応じた適切なHTML要素を選択することが、長期的に保守しやすく品質の高いWebサイトを構築する鍵となります。

javascript:void(0) を置き換えるモダンな代替実装パターン

javascript:void(0) が持つアクセシビリティやセマンティクスの問題を解消するためには、現代のWeb標準に則った適切な代替実装へ移行する必要があります。
基本方針として、ページ遷移やドキュメント間の移動には正しいURLを持つ <a> タグを使用し、アプリケーション内の状態変更やモーダルの開閉といった「アクション(操作)」には <button type="button"> を選択します。また、どうしてもリンクとしての構造を保ちつつ特定のイベント制御を行いたい場合は、JavaScript側で event.preventDefault() を利用します。
このセクションでは、バニラJavaScriptから各モダンフレームワーク(React、Vue.js、jQuery)に至るまで、具体的な代替実装パターンを詳しく解説します。
基本:event.preventDefault() を用いた a タグの制御
どうしても実際のURLへ遷移させずにクリックイベントを発火させたいリンク(例:動的なコンテンツの読み込みや、特定のUI状態の切り替えを伴うナビゲーション項目など)では、href="#" や javascript:void(0) を使うのではなく、適切な href を持たせた上で event.preventDefault() を用いるのが正しいアプローチです。
event.preventDefault() は、ブラウザが要素に対して持っている「既定の動作(デフォルトアクション)」をキャンセルするためのメソッドです。
<!-- 正しいHTML構造とイベント制御の例 -->
<a href="/search/" id="dynamic-link">検索条件を絞り込む</a>
<script>
const link = document.getElementById('dynamic-link');
link.addEventListener('click', (event) => {
// ブラウザのデフォルトのリンク遷移(ページ移動)をキャンセル
event.preventDefault();
// 代わりに独自の非同期処理やUIの更新を実行
executeCustomSearch();
});
</script>
ここで重要なのは、「単に href="#" と preventDefault() を組み合わせるだけでは、ページトップへのスクロールやハッシュの付加といった問題を完全に回避できない場合がある」という点です。もしページ遷移が本来不要な「単なるボタンとしての操作」であれば、後述する <button> 要素を使用するべきです。preventDefault() は、あくまで「リンクとしての性質を持ちながら、既定の遷移を抑止する必要がある特殊なケース」に限定して利用します。
なお、イベントの伝播(バブリング)を止める event.stopPropagation() とは機能が異なります。既定の動作のキャンセルには常に preventDefault() を使用してください。詳細な仕様は、MDN Web DocsのEvent.preventDefault()を参照してください。
HTML原則:ボタンとしての役割なら<button type="button">を選ぶべき理由
「モーダルを開く」「タブを切り替える」「アコーディオンを展開する」といった操作は、文書の移動ではなくアプリケーションの「状態変更」に該当します。これらを実行する場合は、<a> タグを偽装するのではなく、<button type="button"> を選択するのがセマンティックHTMLの基本原則です。
CSSによるデザインで「リンクのように見せたい」という要望がある場合でも、HTMLの構造自体はボタンとして定義し、CSSでスタイリングを調整するのがプロフェッショナルな実装手法となります。
<!-- ❌ 避けるべき実装:リンクをボタン代わりにしている例 -->
<a href="javascript:void(0);" onclick="openModal()">モーダルを開く</a>
<!-- ⭕ 推奨される実装:button要素にtype="button"を指定する例 -->
<button type="button" class="link-styled-button" onclick="openModal()">
モーダルを開く
</button>
/* CSSでボタンのデフォルトスタイルをリセットし、リンクのように見せる例 */
.link-styled-button {
background: none;
border: none;
color: #0066cc;
cursor: pointer;
font: inherit;
padding: 0;
text-decoration: underline;
}
.link-styled-button:hover {
color: #004499;
}
<button type="button"> を使用することで、次のような大きなメリットが標準で得られます。
- キーボードの
EnterキーやSpaceキーによる操作が自動的にサポートされる。 - スクリーンリーダー等の支援技術に対して「ボタン(操作要素)」としての正確な役割が伝わる。
- フォーム内に配置した際、意図しないサブミット(送信)を
type="button"によって確実に防止できる。
Reactでの実装(SyntheticEventとpreventDefault())
Reactの開発環境においても、イベントハンドリングの基本原則はバニラJavaScriptと変わりません。Reactではブラウザ固有のイベントをラップした「合成イベント(SyntheticEvent)」が提供されています。
React公式ドキュメント(イベントへの応答)でも解説されている通り、クリック時のデフォルト動作を抑制するには e.preventDefault() を使用します。
import React from 'react';
function ActionComponent(){
const handleClick = (e) => {
// リンクのデフォルト遷移を防止
e.preventDefault();
console.log("カスタムアクションが実行されました");
};
return (
<div>
{/* リンクの挙動が必要な場合の例 */}
<a href="/fallback-url" onClick={handleClick}>
詳細情報を読み込む
</a>
{/* 単なる操作の場合はボタンを使用する(Reactでも推奨) */}
<button type="button" onClick={() => console.log("ボタンが押されました")}>
設定を変更する
</button>
</div>
);
}
export default ActionComponent;
Reactでコードを記述する際も、「不要な <a> タグを生成し、preventDefault() で無理にボタンとして動かす」ような設計は避け、UIの目的に応じて <a> と <button> を適切に使い分けることが重要です。
Vue.jsでの実装(イベント修飾子@click.prevent)
Vue.jsでは、イベントハンドリングを簡潔に記述するための「イベント修飾子」が用意されており、既定の動作のキャンセルには .prevent 修飾子を使用します。
Vue.js公式ドキュメント(イベントハンドリング)に示されている通り、テンプレート内でメソッドに直接 .prevent を付加することで、冗長なコードを書かずにデフォルトの動作を抑制できます。
<script setup>
import { ref } from 'vue'
const handleAction = () => {
console.log("Vueのイベントが処理されました")
}
</script>
<template>
<div>
<!-- @click.prevent により event.preventDefault() が自動的に適用される -->
<a href="/dashboard" @click.prevent="handleAction">
ダッシュボードを更新
</a>
<!-- 操作目的の場合はbuttonタグを使用する -->
<button type="button" @click="handleAction">
アクションを実行
</button>
</div>
</template>
Vueの .prevent 修飾子や .stop 修飾子(イベント伝播の停止)は非常に強力で便利ですが、「Vueの構文を使うだけでHTMLの意味的な問題が自動的に解決されるわけではない」点に注意してください。<a> タグを使用している限り、セマンティクス上の注意点はバニラJavaScriptと同様に維持されます。
jQueryでの実装(preventDefault()とreturn falseの違い・使い分け)
既存のレガシーなプロジェクトやメンテナンス対象のコードベースでは、jQueryが使われているケースが多く見られます。jQuery環境でリンクの挙動を制御する際は、event.preventDefault() と return false の違いを正確に理解しておく必要があります。
jQueryのイベントハンドラー内で return false を実行すると、「event.preventDefault()(既定動作のキャンセル)」と「event.stopPropagation()(イベントバブリングの停止)」の両方が同時に実行されるという仕様上の挙動があります。そのため、意図せず親要素へのイベント伝播まで止めてしまい、予期せぬバグを引き起こす原因になります。
// ❌ 避けるべき実装:意図せず伝播(バブリング)まで止めてしまう
$('#my-link').on('click', function(e){
// 処理...
return false; // preventDefault と stopPropagation が同時に実行される
});
// ⭕ 推奨される実装:preventDefaultのみを明示的に呼び出す
$('#my-link').on('click', function(e){
e.preventDefault(); // 既定の遷移のみを安全にキャンセル
// 独自の処理を実行
loadDynamicContent();
});
jQuery公式 APIドキュメント(event.preventDefault())でも確認できるように、安全かつ予期せぬ副作用を防ぐ実装としては、必要な処理だけを明示する e.preventDefault() の利用が強く推奨されます。
よくある質問(FAQ)
-
href=”#”とjavascript:void(0)はどちらを使うべき?
-
結論から述べると、どちらも疑似ボタンの代用品として安易に使用するべきではありません。
href="#"の問題点: リンクをクリックした際にページの一番上へスクロールしてしまったり、URLの末尾にハッシュ(#)が付加されて履歴やURLの見た目を汚す原因になります。javascript:void(0)の問題点: 前述の通り、セマンティクス(意味論)の欠如やアクセシビリティの低下、クローラーの巡回阻害を招きます。
画面内の状態変更やアクションを実行したい場合は、
#やjavascript:void(0)でごまかすのではなく、セマンティックな<button type="button">を選択するのが現在のWeb開発における標準的な正解です。
-
大量にある既存のjavascript:void(0)を安全にリファクタリングする手順
-
既存の大規模なWebサイトやアプリケーションに散らばる
javascript:void(0)を一括置換しようとすると、レイアウト崩れやイベントの不具合を引き起こすリスクがあります。安全に移行するための段階的な手順は次の通りです。- 対象コードの検索と一覧化: グレップ検索(例:
href="javascript:void(0")を用いて、サイト内の該当箇所をすべて洗い出し、リスト化します。 - 各要素が担う本来の機能の確認: それぞれの要素が「ページ間の移動(ナビゲーション)」を行っているのか、あるいは「画面内の操作(アクション)」を行っているのかを分類します。
- 適切な要素への置き換え:
- ナビゲーション目的であれば、正しいリンク先(
href)を設定する。 - 操作目的であれば、
<button type="button">に書き換えるか、適切なイベントリスナーと組み合わせる。
- ナビゲーション目的であれば、正しいリンク先(
- CSS・セレクターの確認: タグを
<a>から<button>に変更したことで、既存のCSSセレクター(例:a.buttonなどのスタイル指定)が効かなくなるケースがあるため、スタイルが維持されているか確認します。 - 回帰テストとアクセシビリティ確認: キーボード操作(
TabキーによるフォーカスやEnterキーでの実行)や、フォームの挙動に問題がないかをテストします。
一斉にすべてを変更するのではなく、テンプレート単位やセクション単位で段階的にリファクタリングを進めることをお勧めします。
- 対象コードの検索と一覧化: グレップ検索(例:
-
JavaScriptの処理が実行されない場合は何を確認する?
-
リファクタリング後や新規実装時に「クリックしてもJavaScriptの処理が動かない」「リンクが開かない」といったトラブルに遭遇した場合、次のチェックリストに沿って原因を切り分けてください。
- 開発者ツールのConsole確認: JavaScriptのエラー(未定義の関数、構文エラー、モジュールの読み込み失敗など)が発生していないか最初に確認します。
- イベントリスナーとセレクターの確認: 対象の要素を正しく取得できているか、セレクター(IDやクラス名)に誤りがないかを確認します。
- スクリプトの読み込みタイミング: DOMが完全に構築される前にスクリプトが実行されていないか(
DOMContentLoadedイベントの有無やdefer/async属性の指定)を確認します。 - イベント伝播や既定動作の重複: 意図しない箇所で
event.stopPropagation()や過剰なpreventDefault()が呼び出され、イベントが途中で止まっていないかを確認します。 - CSSによるクリック無効化: CSSプロパティ
pointer-events: none;が適用されていると、要素に対するクリックイベントが一切発火しなくなるため注意が必要です。 - フレームワーク固有の記述ミス: ReactやVueなどの環境では、イベントハンドラーの渡し方(例:JSXでの関数呼び出しの記述ミスや修飾子の付け忘れ)を確認します。
まとめ
本記事では、長年にわたりWeb制作の現場で使用されてきた javascript:void(0) の仕組みや歴史的背景から、現代のWeb開発において非推奨とされる理由、そして適切な代替実装に至るまでを詳しく解説しました。
モダンなWeb開発では、HTMLが持つ本来の意味やアクセシビリティ、そしてSEOや保守性を損なわない設計が求められます。本記事で紹介した代替実装やリファクタリングの手順を参考に、より堅牢で品質の高いコードへとブラッシュアップしていきましょう。
WEBCOACH|副業・フリーランス特化型のオンラインWebデザインスクール



