Справочник · JavaScript
querySelector: как найти элемент на странице
Метод 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, блок не выполняется, ошибки нет. Так же поступай с кнопкой, полем, статусом.
Какие селекторы принимает
| Селектор | Что найдёт |
|---|---|
| "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
Любой CSS-селектор, поиск от document или от элемента.
Только 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 с цифры.