</> Praktum

Главная / JavaScript / querySelector

Справочник · JavaScript

querySelector: как найти элемент на странице

Редакция PraktumОбновлено 8 мин чтенияУровень: новичок

Метод document.querySelector ищет в документе первый элемент, который подходит под CSS-селектор, и возвращает его. Если ничего не нашлось, возвращает null. Селектор пишут строкой: "h1", ".menu", "#send".

Коротко
  • Селектор такой же, как в CSS: тег, класс, id, комбинация.
  • Нет элемента — получишь null. Сначала проверка, потом textContent или обработчик.
  • Искать можно не только в document: у элемента тоже есть querySelector.
  • Родителя с классом ищут через closest, не через цепочку parentNode.
  • Id с цифры экранируй через CSS.escape.

Минимальный пример

Найди заголовок и замени текст. Если элемента нет, условие просто не выполняется.

const title = document.querySelector("h1");
if (title) {
  title.textContent = "Готово";
}

Если заголовка нет, переменная равна null, блок не выполняется, ошибки нет. Так же поступай с кнопкой, полем, статусом.

Какие селекторы принимает

Частые селекторы для querySelector
СелекторЧто найдёт
"h1"Первый заголовок первого уровня
".send"Первый элемент с классом send
"#status"Элемент с id status
"form .send"Кнопка send внутри формы
"a[href^='https']"Первая ссылка, адрес которой начинается с https

Синтаксис совпадает с CSS. Если селектор в таблице стилей работает, его можно отдать querySelector. Сложные селекторы медленнее простых id, но на учебной странице это незаметно. Не ищи элемент в цикле по всей странице через getElementsByTagName и ручное сравнение классов: селектор читается быстрее человеком, и его проще поправить.

Скрипт ставь перед закрывающим body или с атрибутом defer. В head без defer HTML ещё не разобран, заголовка нет, querySelector вернёт null, и ты начнёшь чинить селектор, который ни при чём. В консоли после загрузки тот же селектор уже сработает — отсюда ощущение, что «в файле не работает, а в консоли работает».

Что делать с null

Любое обращение к свойству null даёт TypeError: null.textContent. Поэтому сначала проверка: есть элемент — меняй его. Так же поступай с кнопкой и полем статуса.

const button = document.querySelector(".send");
const status = document.querySelector("#status");
if (button && status) {
  button.addEventListener("click", () => {
    status.textContent = "Отправлено";
  });
}

Поиск внутри элемента, не только у document

У каждого элемента есть те же методы. Так находят цену внутри конкретной карточки, даже если на странице десять цен.

const card = document.querySelector(".card");
if (card) {
  const price = card.querySelector(".price");
  if (price) {
    price.textContent = "120 ₽";
  }
}

Поиск идёт по потомкам card. Сам card в выборку не попадает. Если нужно проверить, подходит ли сам элемент, используй card.matches(".card").

closest: ближайший предок

В обработчике клика часто известен только event.target — например, текст внутри кнопки. Подняться к карточке помогает closest:

document.addEventListener("click", (event) => {
  const card = event.target.closest(".card");
  if (!card) return;
  card.classList.toggle("is-open");
});

Здесь return законен: он внутри функции-обработчика. Если клик не по карточке, обработчик молча выходит.

Id, который начинается с цифры

В HTML5 id может начинаться с цифры, но CSS-селектор #1tab неверен. Браузер не найдёт элемент. Экранируй имя:

const tab = document.querySelector("#" + CSS.escape("1tab"));
if (tab) {
  tab.hidden = false;
}

Лучше не начинать id с цифры. Если разметка чужая — экранирование обязательный навык, а не экзотика.

querySelector или querySelectorAll

querySelector возвращает один элемент или null. querySelectorAll возвращает список, даже пустой, и он не живой: новые элементы в DOM в список сами не попадут. Если нужно повесить обработчик на все кнопки, бери All и перебирай. Если нужна одна кнопка «Отправить» — достаточно querySelector.

querySelector или getElementById

querySelector

Любой CSS-селектор, поиск от document или от элемента.

getElementById

Только id, без решётки, быстрее на крошечную величину. Нет поиска «внутри карточки» тем же API.

Для учебника хватает querySelector везде. Путаница # в getElementById — частая ошибка: туда передают строку без решётки.

Частые ошибки

  • Обращение к textContent, пока результат ещё null.
  • Класс без точки, id без решётки в querySelector.
  • Скрипт в head без defer: HTML ещё нет, всегда null.
  • Ищут id «1tab» селектором #1tab без CSS.escape.
  • Путают querySelector с All и вызывают forEach у элемента.

Доступность

После смены текста кнопки или статуса экранный читатель должен узнать об этом: для живых сообщений используй область с aria-live="polite". Не подменяй фокус без нужды. Поиск в DOM не освобождает от нормальных имени, роли и подписи в HTML.

Поддержка браузерами

querySelector, querySelectorAll и closest работают во всех актуальных браузерах. CSS.escape есть в современных движках; если очень старый WebView, экранируй вручную или не используй id с цифры. Таблица: caniuse.com/queryselector.

Практика

В песочнице найди h1 и кнопку .send. Если элементы есть, по клику меняй текст заголовка. Добавь карточку .card с ценой .price и меняй цену через card.querySelector. Если элемента нет, обработчик не вешай.

Открыть песочницу

Показать решение
const title = document.querySelector("h1");
const button = document.querySelector(".send");
const card = document.querySelector(".card");
if (title && button) {
  button.addEventListener("click", () => {
    title.textContent = "Готово";
  });
}
if (card) {
  const price = card.querySelector(".price");
  if (price) {
    price.textContent = "120 ₽";
  }
}

Частые вопросы

Почему всегда null?

Селектор не совпал или скрипт выполнился до появления HTML. Подключи скрипт внизу body или слушай DOMContentLoaded. Проверь точку у класса: ".send", не "send".

Как найти внутри карточки, а не на всей странице?

Вызови метод у элемента: card.querySelector(".price"). Поиск начнётся с потомков card, а не с document.

Чем closest отличается от parentElement?

closest поднимается по предкам, пока не найдёт совпадение с селектором, включая сам элемент. parentElement — только непосредственный родитель, без селектора.

Почему не находится #1tab?

CSS id не может в селекторе начинаться с цифры без экранирования. Используй document.querySelector("#" + CSS.escape("1tab")) или не начинай id с цифры.

Источники

Ещё в разделе JavaScript