【JavaScript】querySelectorとは?使い方と注意点を初心者向けにわかりやすく解説

はじめに

JavaScriptでウェブページの要素(DOM要素)を操作したいとき、document.querySelector はよく登場します。
とはいえ、初心者の方からすると、「このメソッドでどんなことができるのか」「どう書けばよいのか」がイメージしづらいかもしれません。

本記事では、JavaScriptのDOM操作で重要な querySelector について、できるだけやさしく解説していきます。
クラスやIDを指定した要素の取得方法、複数要素へのアクセスで使う querySelectorAll との違い、実務で活かすためのポイントなどを盛り込んで説明します。

もしまだJavaScript自体を学び始めたばかりであっても、各コード例の意味がわかるように工夫しているので、気軽に読み進めてみてください。

この記事を読むとわかること

  • document.querySelector の基本的な仕組みと使い方
  • クラスやID、属性を使った具体的な要素取得方法
  • 実務で役立つ活用シーンや注意点
  • querySelectorAll との違いやそれぞれのメリット
  • よくある疑問点やエラー時の対応策

ここまで理解できれば、DOM要素を柔軟に操作できるようになり、JavaScriptのフロントエンド開発で役立つ基礎力を高めることができます。

querySelectorとは何か

querySelector は、CSSセレクタの記法を使って、指定した要素をひとつだけ取得するメソッドです。
大まかなイメージとしては「CSSファイルで要素にスタイルを当てるときに書くセレクタ」がそのまま使えると思っていただくとわかりやすいでしょう。

たとえば、HTMLで class="headline" と書かれた要素があるとき、CSSでは .headline と表記します。
同じように document.querySelector(".headline") と書けば、そのクラスを持つ最初の要素をひとつ取得することが可能です。

DOM操作の中での位置付け

JavaScriptが行うDOM操作には、要素を取得してから何かしらの処理を加えるという流れがあります。
クリックイベントを付与したり、テキストを変更したり、スタイルを変更したりと、さまざまな使い方が考えられます。

このとき、「どの要素に対して処理を行うか」が明確になっていないと、後のステップでエラーが発生しやすくなります。
querySelector は、この「どの要素か」をCSSセレクタを使って指定できるので、簡潔かつ直感的に書ける点が特徴です。

従来の要素取得との違い

DOMの要素取得には document.getElementById()document.getElementsByClassName() といった別のメソッドもあります。
しかし、それらは用途が限定されている(IDしか取得できない、クラス名しか指定できないなど)場合が多いので、querySelector を使う方が自由度が高いケースが多いです。
逆に、特定のID要素を1つだけ拾うのであれば document.getElementById() がシンプルな分、可読性が高いと感じる方もいるでしょう。

いずれにせよ、CSSセレクタでまとめて指定できる利便性は大きいため、今では querySelector を中心に考えるケースが増えている印象があります。

querySelectorの基本的な使い方

querySelector は、以下のように書きます。

const element = document.querySelector("セレクタ文字列");

ここで「セレクタ文字列」は、CSSでスタイルを指定するときと同じ記法を使います。
クラスを指定する場合は "."、IDを指定する場合は "#"、HTMLタグ名なら "div" など、いろいろな書き方が可能です。

要素を取得する

HTMLタグを直接指定する方法を見てみましょう。
ここでは、HTMLにたとえば下記のような要素があるとします。

<div>
  <p>段落1</p>
  <p>段落2</p>
</div>

ここで段落要素のうち、最初の p を取りたいときはこう書きます。

const firstParagraph = document.querySelector("p");
console.log(firstParagraph.textContent);

"p" とだけ書くことで最初の p 要素を取得できます。
もし複数の p 要素があっても、querySelector は最初に見つかった1つだけを返すことに注意しましょう。

クラスを取得する

クラス名をセレクタとして指定する場合は、「ドット」を付ける書き方が基本です。
たとえば、下記のように書かれたHTMLがあるとします。

<div class="container">
  <p class="notice">お知らせ1</p>
  <p>特にクラス指定のない段落</p>
  <p class="notice">お知らせ2</p>
</div>

ここで class="notice" を持つ最初の段落を取得したいなら、次のように書きます。

const notice = document.querySelector(".notice");
console.log(notice.textContent);

最初に見つかった class="notice" を持つ要素が返ってくるので、結果的に「お知らせ1」の方が取得されることになります。
複数の .notice をまとめて取得したい場合は、後述する querySelectorAll を使いましょう。

IDを取得する

ID名をセレクタとして指定する場合は、「#」を付けて書きます。
次のHTMLを例に見てください。

<div id="main-banner">
  <p>ようこそ、メインバナーへ</p>
</div>

これを取得するときは以下のようになります。

const mainBanner = document.querySelector("#main-banner");
console.log(mainBanner.textContent);

IDは本来ページ内で一意(ユニーク)に設定されるものなので、querySelector のメリットを存分に感じられる箇所かもしれません。
ただし、同じIDが誤って複数箇所に使われている場合は、最初に見つかった要素だけが返ります。

属性を取得する

クラス名やIDだけではなく、任意の属性を使った要素も取得できます。
たとえば、下記のように data- で始まるカスタム属性を設定するケースがあるかもしれません。

<div data-user-id="1001" class="profile">
  <p>ユーザー名: Alice</p>
</div>

このときは [data-user-id="1001"] と書くことで、属性値が「1001」の要素を取得できます。

const userProfile = document.querySelector('[data-user-id="1001"]');
console.log(userProfile.className); // profile

CSSセレクタで属性を扱う方法と同様の表記ルールを使えるので、実務でもカスタム属性を使った要素を柔軟に指定できます。

querySelectorAllとの違い

querySelectorAll は、指定したセレクタにマッチするすべての要素を取得するためのメソッドです。
先ほどの例でクラス名 .notice の要素が2つあった場合に、それらすべてをまとめて取得したい場合は querySelectorAll を使います。

const notices = document.querySelectorAll(".notice");
console.log(notices.length); // 2が表示されるイメージ

querySelectorquerySelectorAll の違いは、「最初の1つを返すか」「すべて返すか」という部分です。
取得した要素を一括で処理したいときは querySelectorAll が便利ですが、まずは1つの要素をしっかり選択したいときに querySelector を使いましょう。

なお、querySelectorAll が返すのは「NodeList」というオブジェクトで、JavaScriptの配列のように扱える部分と扱えない部分があります。
ただし、初心者の方は、単純に「繰り返し処理で複数の要素にアクセスできる」程度に考えておくと理解しやすいです。

実務での活用シーン

初心者の方にとっては、どこで querySelector を使えば実務に活かせるのかイメージがわかないかもしれません。
そこで、よくあるシーンをいくつか紹介します。

動的にUI要素を操作するとき

たとえば、メニューの開閉や、ページ内の一部だけを動的に書き換えるような場面があります。
クリックされるボタン(要素)を querySelector で取得し、そこにイベントリスナーをつけるパターンがよく登場します。

const toggleButton = document.querySelector("#menu-toggle");
toggleButton.addEventListener("click", () => {
  const menu = document.querySelector(".header-menu");
  menu.classList.toggle("open");
});

上記の例では、IDが menu-toggle のボタンを取得してクリックイベントを設定しています。
クリックされたら .header-menu クラスを持つ要素のクラスを切り替えることで、メニューを開いたり閉じたりするわけです。

フォーム入力の検証やリアルタイムチェック

フォームの入力内容をリアルタイムで検証(バリデーション)するケースは多いでしょう。
querySelector でフォーム要素を取得し、値の状態に応じてメッセージを表示したり、入力枠の色を変えたりできます。

const usernameField = document.querySelector("#username");
usernameField.addEventListener("input", (e) => {
  const currentValue = e.target.value;
  const errorBox = document.querySelector(".error-message");
  
  if (currentValue.trim() === "") {
    errorBox.textContent = "ユーザー名は必須です";
  } else {
    errorBox.textContent = "";
  }
});

実務では、ユーザーの操作に合わせてページの見た目やメッセージを動的に変更する必要があります。
そうした場面で、要素を的確に選択するための手段として querySelector が大いに役立ちます。

よくある疑問と注意点

使い始めると、「要素が取得できない」「エラーが出る」といったトラブルに遭遇することがあります。
いくつかよくある疑問や注意点を整理しておきましょう。

取得できなかった時の対応

querySelector で取得した要素が null になる場合があります。
これは、指定したセレクタに該当する要素が見つからなかったときに起こる現象です。

次のように対策しましょう。

const element = document.querySelector(".non-existing-class");

if (element === null) {
  console.log("要素が見つかりませんでした。");
} else {
  console.log(element.textContent);
}

実務では、HTML構造が変更されたり、要素がまだレンダリングされていなかったりすることも考えられます。
そのため、必ず要素が取得できるとは限らない点を把握しておきましょう。

大量の要素を扱う時のパフォーマンス

「ページ内のあらゆるタグを取得し、一括で処理する」というような場合、querySelectorAll を多用するとパフォーマンスが落ちる可能性があります。
とくに要素数が多い大型ページでは、セレクタの指定をシンプルにする、または使う要素を限定して取得するなどの工夫が必要です。

複雑なセレクタを使うほど、DOMの探索が増えて処理が重くなる場合があります。
シンプルなセレクタを活用し、必要最低限の要素のみ取得することを意識すると良いでしょう。

また、一度取得した要素を変数に格納して再利用する形にしておくと、毎回DOMを検索しなくて済むので効率が上がります。

効率的な書き方と読みやすいコード

実務では、可読性と保守性を考慮してコードを書くことが大切です。
querySelector を使うにしても、なるべくわかりやすい書き方を心がけておきましょう。

チェーンメソッドの活用

ときどき見かけるのは、querySelector した要素に対して、さらに同じメソッドで子要素を取得するやり方です。
たとえば、以下のようなHTML構造を想定します。

<div class="wrapper">
  <div class="card">
    <p class="title">カードタイトル</p>
  </div>
</div>

.wrapper の中にある .card の中にある .title を取りたい」場合に、次のように書くことができます。

const titleElement = document
  .querySelector(".wrapper")
  .querySelector(".card")
  .querySelector(".title");

console.log(titleElement.textContent);

このように、取得した要素からさらに querySelector を繋げる(チェーンする)形です。
ただし、多用しすぎると可読性が下がるケースもあります。
慣れないうちは1ステップずつ変数に入れた方が分かりやすいかもしれません。

ネストされた要素の選択方法

ネスト(入れ子)構造が深い場合、セレクタ同士を組み合わせてシンプルに書くこともできます。
先ほどの例であれば、CSSの記法に準じて .wrapper .card .title と書くことが可能です。

const titleElement = document.querySelector(".wrapper .card .title");

慣れてくると、このようなCSSの書き方そのままを使う方がコードの意図がわかりやすいでしょう。
「Wrapper内のCardにあるTitleを取りたいんだな」というのがひと目で伝わります。

実務で困ったときの対処法

ここでは、「想定どおりの要素が取得できない」「エラーで動かない」といったときの基本的な考え方を解説します。

1. セレクタの記述ミスを確認する

CSSセレクタは、ピリオドやシャープ、属性指定など、記号が並ぶためミスに気づきづらいことがあります。
まずはセレクタを書き間違えていないか、HTMLのクラス名やIDと正しくマッチしているかをチェックしましょう。

2. DOMの読み込みタイミングを確認する

スクリプトがHTMLの要素を操作するとき、まだその要素が読み込まれていない段階で querySelector を呼び出すと null が返ってしまうことがあります。
たとえば、<head> の中でスクリプトを読み込んでいる場合、DOMが完成していない可能性があるでしょう。
対策としては、<body> の最後でスクリプトを呼び出すか、あるいはDOM読み込み完了イベントを使うなどの方法があります。

3. 要素が動的に生成される場合の動きを検証する

フレームワークなどで要素を追加・削除している場合、コードが走ったタイミングでは該当要素が存在しないかもしれません。
このように動的生成される要素を扱うときは、生成後の状態を把握しながら querySelector を呼ぶ仕組みが必要になります。

遅延ロードや非同期処理で要素が後から追加される場合は、いつでもquerySelectorで取得できるわけではありません。
非同期処理が完了するタイミングを検知して、要素が確実に存在する段階でアクセスする必要があります。

まとめ

JavaScriptの document.querySelector は、CSSセレクタを使って柔軟にDOM要素を取得できる便利なメソッドです。
要素を1つだけ取得したいときは querySelector、複数の要素をまとめて取得したい場合は querySelectorAll を使い分けるというのが基本の考え方になります。

クラスやID、属性など、実務でも頻繁に使われるさまざまな指定が可能なので、UI操作からフォームバリデーションまで多彩なシーンに対応できます。
ただし、該当要素が存在しない場合は null が返ることや、大量の要素を取得するとパフォーマンスが低下することには気をつけてください。

最初のうちは、「セレクタが正しいか?」「DOMの読み込みタイミングは正しいか?」 といった基本的なところをしっかり押さえるのが重要です。
そこを踏まえれば、フロントエンド開発のさまざまな場面で、スムーズに要素操作ができるようになるはずです。
ぜひ本記事の具体例を参考に、実際のコードでどんどん試してみてください。

JavaScriptをマスターしよう

この記事で学んだJavaScriptの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。