querySelector とは何か
querySelector は、CSS セレクタで「最初に一致した1つの要素」を取得するためのメソッドです。返り値は要素か、見つからなければ null。ここが重要です:id やクラスだけでなく、タグ、属性、階層、擬似クラス(:first-child など)まで、CSS と同じ書き方で柔軟に絞り込めるため、DOM フックの自由度が非常に高いことが最大の強みです。
基本の使い方(CSS セレクタで一発取得)
id・クラス・タグで取る
<h1 id="title">こんにちは</h1>
<p class="msg">説明</p>
<div>ボックス</div>
<script>
const a = document.querySelector("#title"); // id
const b = document.querySelector(".msg"); // クラス(最初の1件)
const c = document.querySelector("div"); // タグ(最初の1件)
console.log(a.textContent, b.textContent, c.textContent);
</script>
HTML属性や階層で柔軟に絞る
<div class="card"><button data-role="buy">購入</button></div>
<div class="card"><button data-role="info">詳細</button></div>
<script>
// card の中にある “buy” ボタンだけ
const buyBtn = document.querySelector(".card button[data-role='buy']");
buyBtn.textContent = "購入する";
</script>
HTMLここが重要です:単純な id/クラス取得はもちろん、構造や属性まで含めて「1本のセレクタ」で狙い撃ちできるのが querySelector の利点です。
スコープの絞り込み(document だけでなく親要素からも)
document から探せばページ全体が対象ですが、親要素から呼べば「その要素配下だけ」を検索します。大規模ページでは、スコープを絞って意図しない混入を防ぐのがコツです。
const panel = document.getElementById("panel");
const innerButton = panel.querySelector(".btn"); // panel配下の .btn だけ
JavaScriptここが重要です:機能ブロック(コンポーネント)単位でスコープを限ると、クラス名の衝突や期待外のヒットを避けられ、保守性が上がります。
返り値とタイミング(null を正しく扱う)
querySelector は見つからないと null を返します。早すぎるタイミング(DOM 未構築)で呼ぶと null になりがちなので、DOM 構築後に触るのが基本です。
<script>
document.addEventListener("DOMContentLoaded", () => {
const el = document.querySelector("#title");
if (!el) {
console.warn("#title が見つかりません");
return;
}
el.textContent = "ようこそ";
});
</script>
HTMLdefer を付けた外部スクリプトなら、DOM 構築完了直前に実行されるため、毎回イベント待ちを書く必要が減ります。
<script src="app.js" defer></script>
HTMLここが重要です:null ガードを癖にし、スクリプトは defer(または DOMContentLoaded)で実行する。これだけで初期化の安定性が段違いになります。
querySelectorAll・getElementById との使い分け
- 1件だけ欲しいなら querySelector。複数件欲しいなら querySelectorAll(静的 NodeList)。
- id 一意なら getElementById が最速・明確(読みやすさ重視)。構造や属性で柔軟に絞るなら querySelector。
// 1件だけ
const title = document.querySelector("#title");
// 複数件(静的なスナップショット)
const items = document.querySelectorAll(".item"); // NodeList
items.forEach(el => el.classList.add("bound"));
// id があるなら最短ルート
const fast = document.getElementById("title");
JavaScriptここが重要です:迷ったら「id があるなら getElementById」「条件が複雑なら querySelector」「複数なら querySelectorAll」。この軸を守ると読みやすく壊れにくいコードになります。
現場で役立つセレクタの書き方(深掘りのコツ)
data-* をフックにする(JS 用メタ)
<button class="btn" data-sku="SKU-123">購入</button>
<script>
const btn = document.querySelector(".btn[data-sku='SKU-123']");
console.log(btn.dataset.sku); // "SKU-123"
</script>
HTML兄弟・子孫・親を意識した書き方
// 直下の子だけ(>)
const title = document.querySelector(".card > .title");
// 近い祖先を探す(closest は Element メソッド)
const btn = document.querySelector(".buy-button");
const card = btn.closest(".card"); // セレクタで親を安全に特定
JavaScript特殊文字を含む id/クラスはエスケープ
<div id="user.name">...</div>
<script>
// ドットなど特殊文字はバックスラッシュでエスケープ
const el = document.querySelector("#user\\.name");
</script>
HTMLここが重要です:見た目用クラスと JS フック(data-* や安定した id)を分け、セレクタは「短く、変わりにくく」書く。エスケープが必要な命名は避けるのが理想です。
イベントと組み合わせる定番パターン
querySelector で要素を取り、addEventListener で振る舞いを付けます。表示制御はクラス切り替えが基本です。
<button id="toggle">切り替え</button>
<div id="panel" class="hidden">内容</div>
<script defer>
const toggle = document.querySelector("#toggle");
const panel = document.querySelector("#panel");
toggle.addEventListener("click", () => {
const hidden = panel.classList.toggle("hidden");
toggle.textContent = hidden ? "開く" : "閉じる";
});
</script>
HTMLここが重要です:HTML は「意味と構造」、JS は「動き」。見た目はクラスで統一、テキストは textContent で安全に入れる。役割分担ができているほど壊れません。
よくある落とし穴(精度・性能・可読性のバランス)
- セレクタが長すぎる(DOM 構造変更に弱くなる)。短く、安定したフックで。
- DOM 未構築で実行して null。defer/DOMContentLoaded でタイミングを合わせる。
- innerHTML 乱用で XSS とイベント喪失。基本は要素生成+textContent+classList。
- 何度も同じセレクタで検索して無駄が増える。必要なら一度取得して変数に保持。
ここが重要です:セレクタは「短い・安定・意図が明確」。タイミングは「遅すぎず早すぎず」。この2点を守るだけで、querySelector は最も頼れる相棒になります。
まとめ
querySelector は「CSS セレクタで最初の一致を1件取る」柔軟な取得メソッドです。document だけでなく親要素からも検索でき、構造・属性・状態まで含めて精密に狙えます。null ガードと defer/DOMContentLoaded を徹底し、id は getElementById、複数は querySelectorAll と使い分ける。data-* をフックにしてセレクタを短く保ち、見た目はクラスで制御する——この軸が身につけば、要素取得は速く、正確で、保守も楽になります。
