«Объектная модель документа» по другому «DOM-дерево» это не что иное, как интерфейс доступа к веб-странице. И основная задача этого интерфейса - обеспечить возможность для редактирования контента и манипуляции со структурой и стилями документа. Давайте разберем понятие по порядку.

Как строится веб-страница в браузере

Процесс при котором браузер получив исходный код выводит интерактивную и стилизованную страницу в окно браузера называется «Критический путь рендера» (“Critical Rendering Path”). Хотя этот процесс, сам по себе, состоит из множества шагов, мы можем условно выделить два этапа. Первый этап заключается в том что браузер парсит исходный код, чтобы выяснить что конкретно должно быть прорисовано на странице, а второй этап это уже сам рендер.

HTML-to-Render-Tree-to-Final

Результат выполнения первого этапа это так называемое «рендер-дерево». Рендер-дерево это представление HTML элементов, которое должны быть отрисованы вместе со связанными с ними стилями. Для того чтобы построить такое дерево браузеру нужно две вещи:

  1. CSSOM - Представление стилей связанных с элементами на странице.
  2. DOM - Объектное представление HTML элементов на странице.

Как создается DOM (и как он выглядит)

DOM, как уже было сказано, это объектное представление кода HTML документа, т.е другими словами объект свойства которого это имена тегов HTML с учетом вложенности и дополнительной информации - такой как: атрибуты тегов, текстовое содержимое и т.д. Однако, есть некоторые отличия, которые мы рассмотрим ниже, но, в целом, все они связаны с попыткой конвертированного в объект HTML соответствовать нуждам программ которые его используют.

Структурно DOM принимает вид упорядоченного дерева, потому как оно представлено в виде единственного родительского элемента от которого ответвляются все остальные “ветви”, каждая их которых имеет свои дочерние элементы “листья дерева”. В нашем случае главный родительский элемент это тег <html>, дочерние ответвления это другие вложенные теги и элементы 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>

этот HTML документ может быть представлен в виде следующего дерева:

  • html
    • head
      • title
        • My first web page
  • body
    • h1
      • Hello, world!
    • p
      • How are you?

Чем DOM НЕ является

Из примера выше, может показаться что DOM это точное (1 к 1) отображение исходного кода, который вы можете наблюдать в вашем devTools. Однако, как я отмечал ранее, тут есть отличия. Чтобы полностью понять что такое DOM-дерево. Мы должны рассмотреть чем оно НЕ является.

DOM это не ваш исходный код

Несмотря на то, что DOM строится по исходному коду HTML документа, не всегда это одно и то же. Есть два случая, в которых DOM может отличаться от исходного HTML:

1. Когда HTML не валидный.

DOM это интерфейс к валидному HTML документу. Во время его создания, браузер может откорректировать некоторые невалидные элементы.

Для примера рассмотрим следующий документ:

<!DOCTYPE html>
<html>
    Hello, world!
</html>

В документе отсутствуют <head> и <body>, которые нужны для того чтобы документ был валидным. Но, если мы взглянем на DOM дерево, полученное в результате, мы увидим что это было исправлено:

  • html
    • head
    • body
      • Hello, world!

2. Когда DOM изменяется через javascript.

Вместе с тем, что это интерфейс для отображения HTML документа, DOM также может быть модифицирован, тем самым превратившись в динамический ресурс.

К примеру, мы можем добавлять новые вершины в DOM дерево

var newParagraph = document.createElement('p');
var paragraphContent = document.createTextNode("I'm new!");
newParagraph.appendChild(paragraphContent);
document.body.appendChild(newParagraph);

Эта инструкция обновит наше DOM-дерево, но, исходный HTML код конечно же не изменится.

DOM это не то что вы видите в браузере (т.е это не render-tree)

То что вы видите в окне браузера, это рендер-дерево (render-tree), которое, как упоминалось ранее это комбинация DOM и CSSOM. Главное отличие DOM от Render-tree в том, что последнее содержит в себе именно то, и только то, что будет отрисовано на экране.

Из-за того, что Render-tree заинтересовано только в том что должно быть отрисовано, оно не содержит элементов, которые визуально скрыты от пользователей.

Например это могут быть все элементы, для которых выставлен ‘display:none’ в CSS стилях.

<!DOCTYPE html>
<html lang="en">
    <head></head>
    <body>
        <h1>Hello, world!</h1>
        <p style="display: none;">How are you?</p>
    </body>
</html>

В примере выше, DOM будет содержать элемент <p>:

  • html
    • head
    • body
      • h1
      • p

При этом Render-tree, а значит и то что будет отображено в окне браузера - этого элемента не содержит и будет выглядеть так:

  • html
    • body
      • h1

DOM это не то же самое что находится в DevTools.

Разница тут не очевидна, т.к инспектор элементов в DevTools показывает максимально приближенную к DOM версию дерева. Однако, инспектор в DevTools включает в себя дополнительную информацию которой нет в DOM.

Лучший пример такой информации это псевдо-элементы. Псевдо-элементы создаются с помощью селекторов ::after и ::before берутся из CSSOM как части готового Render-tree, но, при этом, технически не являются частью DOM. Это потому, что DOM построен по HTML документу, не включая стили применяемые к элементу.

Несмотря на то, что псевдо-элементы не являются частью DOM-дерева, они все равно присутствуют в нашем инспекторе элементов devTools.

Pseudo-element-in-devtools-inspector

Именно поэтому псевдо-элементы “не видны” из javascript, потому что они не являются частью DOM-дерева.

Вывод

DOM-дерево это интерфейс к HTML-документу. Оно используется браузерами на первом шаге процесса рендера страницы, для определения того что необходимо отрисовать, и, программами на javascript - для модификации содержимого, структуры или же для стилизации контента страницы.

Несмотря на сходства с остальными формами исходного HTML-кода, DOM имеет ряд отличий:

  1. Это всегда только валидный HTML
  2. Это живая модель которая может быть изменена с помощью javascript
  3. Не содержит псевдоэлементов (::before, ::after и т.д.)
  4. Не содержит скрытых элементов (display:none; и т.д.)

Данный текст это мой вольный перевод оригинальной статьи Ire Aderinokun - What, exactly, is the DOM?