いつもどおり書いたはずのハンバーガーメニューが、特定のページだけ動かない——コーディングをしていると出くわす、地味にハマりやすいトラブルです。
結論から言うと、原因は存在しない要素に対してaddEventListenerを実行していることで、コンソールには「Cannot read properties of null」というエラーが出ます。解決策は、要素があるときだけイベントを登録するよう、if文でガードすることです。この記事では、症状・エラー内容・原因・対策を順に解説します。
目次
スマホサイトでよく見る「三」のボタン。タップするとメニューが開く、あの仕組みです。該当のコードは次のような形でした。
//hamburger menu
function hamburger() {
document.getElementById('line1').classList.toggle('active');
document.getElementById('line2').classList.toggle('active');
document.getElementById('line3').classList.toggle('active');
document.getElementById('hamburger-menu').classList.toggle('active');
}
document.getElementById('hamburger').addEventListener('click', function () {
hamburger();
});
記述ミスがないか何度も見直しても、原因が見つからない。こんなときは、まずブラウザのコンソールを確認するのが近道です。
デベロッパーツールのコンソールを開くと、次のエラーが出ていました。
Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')
末尾の(reading 'addEventListener')が、どこでつまずいたかを教えてくれています。「nullに対してaddEventListenerを読もうとした」という意味です。
document.getElementById('hamburger')は、対象のIDを持つ要素が見つからないとnullを返します。今回は、ハンバーガーメニューを使わないページがサイト内にあり、そのページにはid="hamburger"の要素が存在しませんでした。
その結果、nullに対して.addEventListener(...)を呼び出してしまい、エラーが発生していたのです。JavaScriptはnullのプロパティを読めないため、ここで処理が止まります。全ページ共通のJSに書いていたことが、このトラブルの引き金でした。
解決策はシンプルです。取得した要素を変数に入れ、それが存在する(nullでない)ときだけaddEventListenerを実行するよう、if文で囲みます。
//hamburger menu
function hamburger() {
document.getElementById('line1').classList.toggle('active');
document.getElementById('line2').classList.toggle('active');
document.getElementById('line3').classList.toggle('active');
document.getElementById('hamburger-menu').classList.toggle('active');
}
const hamburgerbtn = document.getElementById('hamburger');
if (hamburgerbtn) {
hamburgerbtn.addEventListener('click', function () {
hamburger();
});
}
if (hamburgerbtn)で、要素が取得できたページでだけイベントを登録します。ハンバーガーメニューがないページではifの中に入らないので、エラーは発生しません。要素の有無にかかわらず、同じJSを全ページで読み込めるようになります。
この対策の背景には、getElementByIdの性質があります。要素が見つかったときはその要素を、見つからなかったときはnullを返す——この仕様を知っていれば、「取得結果はnullかもしれない」と身構えられます。
DOMを取得してから操作するコードは、要素が存在する前提で書きがちです。しかし、全ページ共通のJSでは「このページにその要素はあるか」が常に問われます。取得と操作の間に存在チェックを1つ挟む習慣をつけておくと、この手のエラーをまとめて防げます。
より短く書きたい場合は、オプショナルチェーン(?.)も使えます。document.getElementById('hamburger')?.addEventListener('click', hamburger);のように書くと、要素がnullのときはaddEventListenerを呼ばずにスキップします。if文を書かずに存在チェックできるので、コードがすっきりします。
なお、要素が実際にはページにあるのにnullになる場合は、スクリプトの読み込み位置が原因のこともあります。要素より前でスクリプトが実行されると、その時点ではまだDOMに存在せずnullになります。その場合は</body>の直前にスクリプトを置くか、DOMContentLoadedの完了を待ってから実行すると解決します。
getElementByIdは要素が見つからないとnullを返すif文でチェックし、存在するときだけaddEventListenerを実行するよく使うコードほど「動いて当然」と思い込みがちですが、ページの条件が変わると同じコードでもエラーになります。存在チェックのひと手間で、使い回すコードがぐっと堅牢になります。