Объектная модель документа: что такое DOM и чем не является?
Что такое DOM, и где ее искать? Разбираемся, как выглядит объектная модель документа, для чего нужна и чем отличается от простого HTML-кода.
Объектная модель документа, aka DOM, – это интерфейс, с помощью которого программы могут работать с контентом, структурой и стилями веб-страницы. Проще говоря – это набор методов, которые можно вызвать, и свойств, к которым можно обратиться.
Чтобы лучше разобраться, что такое объектная модель документа, давайте посмотрим, как она создается.
Создание веб-страницы
Путь от исходного HTML в вашем файле до отображения в браузере оформленной страницы, с которой можно взаимодействовать, называется критическим путем отрисовки (critical rendering path). Его можно разбить на два больших этапа:
- анализ кода и построение дерева рендера (render tree);
- непосредственная отрисовка страницы.
Дерево рендера, или дерево визуализации, – это специальная структура, состоящая из HTML-элементов, которые будут отображены на странице, и связанных с ними стилей. Это дерево собирается из двух компонентов:
- CSSOM (объектная модель CSS) – все стили документа;
- DOM – все элементы страницы.
Таким образом, формирование DOM предшествует формированию готовой страницы.
Как выглядит DOM?
DOM – это объектное представление исходного HTML-документа, попытка преобразовать его структуру и содержимое в объектную модель, с которой смогли бы работать различные программы.
В ближайшем приближении DOM – это "дерево узлов" (node tree). У него единый корень, который разветвляется на множество дочерних ветвей, каждая из которых может ветвиться сама и заканчивается "листьями". Корень – это элемент html
, а ветви – вложенные элементы.
Для примера возьмем простой документ:
<!doctype html> <html lang="en"> <head> <title>My first web page</title> </head> <body> <h1>Hello, world!</h1> <p>How are you?</p> </body> </html>
Он может быть представлен в виде дерева узлов:
Чем DOM не является?
Возможно, пример выше заставил вас подумать, что DOM – это то же самое, что и исходный HTML-документ, или то, что вы видите в браузере в консоли разработчика. Это не совсем так. И вместо того, чтобы описывать, что такое DOM, попробуем разобраться, чем DOM не является.
DOM – это не HTML-код
Безусловно, DOM создается из исходного HTML-кода. Но объектная модель не всегда полностью соответствует своему прообразу. Почему так происходит?
Невалидный HTML
DOM всегда валидна, поэтому в процессе создания браузер может поправить некоторые ошибки исходного кода, например, добавить пропущенный tbody или закрыть какой-нибудь незакрытый тег.
Например, такой невалидный HTML-код:
<!doctype html> <html> Hello, world! </html>
превратится в такую валидную объектную модель:
Браузер самостоятельно добавил теги head и body, которые требуются по спецификации.
Модификация с помощью JavaScript
DOM позволяет не только просматривать содержимое страницы, но и взаимодействовать с ним, изменять. Это не статичное отображение, а живой ресурс.
Например, с помощью JavaScript можно создать дополнительные элементы:
var newParagraph = document.createElement("p"); var paragraphContent = document.createTextNode("I'm new!"); newParagraph.appendChild(paragraphContent); document.body.appendChild(newParagraph);
DOM после этого обновится, а исходный HTML, разумеется, останется таким же, как был.
Страница может заполняться контентом, полученным асинхронно с сервера с помощью AJAX-запросов. Эта операция также не затрагивает исходный код, но изменяет объектную модель.
DOM – это не код страницы
Аналогично, то, что вы видите, нажав Просмотреть код страницы (горячая комбинация Ctrl+U
), также не является объектной моделью документа, ведь по сути это и есть исходный HTML-код.
Впрочем, если вы используете какой-нибудь шаблонизатор и рендерите HTML на сервере, исходный код страницы будет отличаться от того кода, который вы видите в браузере.
DOM – это не дерево рендера
Дерево рендера – это то, что вы видите, открыв страницу в браузере. Вы помните, что оно образуется из комбинации DOM и CSSOM.
Дерево рендера состоит только из видимых на экране элементов, и это его ключевое отличие от DOM. Например, вы не найдете здесь элементов, для которых установлено CSS-правило display: none. Они не видны, не занимают места на странице и не участвуют в рендере.
<!doctype html> <html lang="en"> <head></head> <body> <h1>Hello, world!</h1> <p style="display: none;">How are you?</p> </body> </html>
Видите скрытый с помощью инлайнового стиля параграф?
Вы можете найти его в DOM:
но не в дереве рендера:
DOM – это не содержимое DevTools
Тут разница не такая очевидная, как в случае дерева рендеринга. Панель разработчика имеет максимально близкую к DOM реализацию, но все же они не идентичны. В DevTools можно найти информацию, которой нет в DOM.
Лучший пример этого – псевдоэлементы CSS, созданные с помощью селекторов :before
и :after
. Они являются частью CSSOM и дерева рендеринга, но в DOM отсутствуют. Дело в том, что DOM строится на основе HTML и не учитывает CSS-стили.
Так что в инструментах разработчика псевдоэлементы есть:
а в DOM – нет. Именно поэтому с ними нельзя взаимодействовать из JavaScript, ведь они не являются частью объектной модели документа.
Что же такое объектная модель документа?
DOM – это интерфейс HTML-страницы и первый этап ее отрисовки в браузере.
DOM очень близок к другим формам представления исходного HTML-кода, но все же не идентичен им.
Основные характеристики объектной модели:
- основана на валидном HTML-коде;
- может быть модифицирована из JavaScript;
- не включает псевдоэлементы, созданные из CSS;
- включает скрытые элементы (
display: none
).
Объектная модель документа – очень полезная штука. Благодаря ей JavaScript может взаимодействовать со страницей, изменять ее содержимое, структуру и стили. Именно благодаря DOM вы можете отслеживать клиентские события.
Например, повесим обработчик события mouseenter на элемент заголовка:
document.getElementById('firstHeading').addEventListener('mouseenter', function() { console.log('The Mouse Entered'); }
Элемент заголовка здесь – это узел DOM-дерева, к которому мы смогли обратиться с помощью DOM-метода addEventListener. Когда событие наведения мыши произойдет, DOM-элемент распространит его выше по дереву DOM и сообщит нам об этом.
DOM – понятие, специфичное для браузерной среды выполнения кода. Это не JavaScript, а лишь API, которым JavaScript может пользоваться.
Оригинальная статья: What, exactly, is the DOM?