Базові поняття DOM
1. Що таке DOM?
Відповідь:
DOM (Document Object Model) — це об’єктне представлення HTML-документа, яке браузер створює після того, як завантажує HTML-код. DOM дозволяє JavaScript отримувати доступ до вмісту, структури та стилів сторінки та змінювати їх динамічно.
- DOM перетворює HTML у дерево вузлів (nodes).
- Кожен HTML елемент стає об’єктом, з властивостями та методами.
- DOM є частиною Web API, а не частиною самого JavaScript.
🔍 При завантаженні сторінки браузер виконує такі операції:
1. Парсинг HTML
- Коли браузер отримує HTML-документ від сервера, він починає обробляти його пострічково.
- HTML аналізується і поступово перетворюється у DOM-дерево. Кожен тег, атрибут і текст стає відповідним вузлом у цьому дереві.
2. Побудова DOM-дерева
- DOM-дерево формується на основі структури HTML. Це дозволяє JavaScript та іншим скриптам взаємодіяти з елементами сторінки.
- Вузли створюються відповідно до елементів HTML, починаючи з
<!DOCTYPE>
і кореневого тегу<html>
.
3. Виявлення інших ресурсів
- Під час парсингу HTML браузер виявляє посилання на зовнішні ресурси (CSS, JavaScript, зображення).
- Ці ресурси завантажуються паралельно, але їх обробка може впливати на DOM.
4. Блокування при виконанні JavaScript
- Якщо браузер зустрічає JavaScript, він може зупинити парсинг HTML до тих пір, поки скрипт не буде виконаний (якщо він не є async або defer).
- JavaScript може змінювати DOM на льоту: додавати, видаляти або змінювати вузли.
5. Зв’язок з CSSOM
- Після побудови DOM-дерева, браузер інтегрує його з CSS Object Model (CSSOM), створюючи рендер-дерево.
- Це дозволяє розуміти, як стилі застосовуються до елементів DOM.
6. Рендеринг (Rendering)
- На основі DOM і CSSOM браузер визначає, що і як повинно відображатися на екрані.
- DOM-дерево оновлюється в реальному часі, якщо скрипти або дії користувача змінюють структуру HTML.
7. Маніпуляція DOM JavaScript
- JavaScript може використовувати DOM API для:
- Додавання нових елементів (наприклад, через
createElement
іappendChild
). - Зміни існуючих елементів (наприклад, через
textContent
абоclassList
). - Обробки подій DOM (наприклад, кліки, наведення тощо).
- Додавання нових елементів (наприклад, через
8. Оновлення та перерисовка
- Зміни в DOM, викликані JavaScript або CSS, призводять до перерисовки (repaint) або перерахунку макета (reflow). Це впливає на продуктивність.
Таким чином, основне завдання браузера при завантаженні сторінки — створити DOM-дерево, яке стане основою для відображення сторінки та її подальшої взаємодії з JavaScript. Якщо потрібні приклади роботи з DOM, дайте знати! 😊
2. Яка структура DOM?
DOM — це ієрархічне дерево вузлів, де:
- Кожен HTML елемент — це вузол-елемент (Element Node).
- Текст всередині елементів і пробіли — це текстовий вузол (Text Node).
- Коментарі — це comment node.
document
— це кореневий об’єкт (root), який представляє всю сторінку.
🔽 Наприклад, HTML:
htmlКопіюватиРедагувати<body>
<h1>Hello</h1>
</body>
🧠 DOM структура виглядатиме так:
document
└── html
└── body
└── h1
└── Text node: "Hello"
3. Чим відрізняється document
, window
, document.documentElement
, document.body
?
Відповідь:
document.body
— це <body>
тег — основний вміст сторінки.
window
— глобальний об’єкт браузера. Він містить все: document
, console
, setTimeout
і т.д.
document
— властивість window
, яка представляє поточний HTML документ.
document.documentElement
— це <html>
тег. Найвищий вузол елементу DOM.
5. Які є типи вузлів (nodes) у DOM?
У DOM існує кілька типів вузлів, найважливіші з них:
- Element nodes – HTML-елементи (
<div>
,<span>
,<input>
і т.д.) - Text nodes – текст усередині елементів (
"Привіт"
всередині<p>
) - Comment nodes – коментарі
<!-- коментар -->
- Document node – сам документ (
document
) - DocumentFragment node – фрагмент документу, корисний для оптимізації вставки кількох елементів
Можна перевірити тип вузла:
element.nodeType === 1 // Element
text.nodeType === 3 // Text
comment.nodeType === 8 // Comment
//Це дозволяє відфільтровувати непотрібні вузли під час обходу DOM.
6. Які методи використовуються для доступу до елементів в DOM?
Відповідь:
document.getElementById('id') // Повертає один елемент
document.getElementsByClassName('class') // HTMLCollection
document.getElementsByTagName('div') // HTMLCollection
document.querySelector('селектор') // Перший збіг
document.querySelectorAll('селектор') // NodeListdocument.
getElementsByName
('селектор') // NodeList
Важливо:
HTMLCollection
і NodeList
схожі, але NodeList
може бути статичним (не оновлюється після змін), а HTMLCollection
— живий.
getElementById
— найшвидший, бо шукає лише по ID.
querySelector/querySelectorAll
— найгнучкіші, бо дозволяють використовувати CSS-селектори.
7. Що таке document
у JavaScript?
document
— це глобальний об’єкт, який представляє DOM поточного HTML-документа. Він надає API для доступу до вузлів, елементів, атрибутів, створення та маніпуляції ними.
Основні методи:
document.getElementById(id)
document.querySelector(selector)
document.createElement(tagName)
📌 Важливо: об’єкт document
існує тільки у контексті браузера. У Node.js його немає без бібліотек типу JSDOM.
8. У чому різниця між getElementById
, getElementsByClassName
, querySelector
і querySelectorAll
?
Це всі методи для пошуку елементів у DOM:
Метод | Повертає | Пошук за | Живий? |
---|---|---|---|
getElementById(id) | Один елемент | id | ❌ |
getElementsByClassName(class) | HTMLCollection | class | ✅ |
getElementsByTagName(tag) | HTMLCollection | tag | ✅ |
querySelector(selector) | Один елемент | CSS селектор | ❌ |
querySelectorAll(selector) | NodeList | CSS селектор | ❌ |
document.querySelector(“.card”); // Перший елемент з класом card document.querySelectorAll(“.card”); // Всі з класом card
HTMLCollection — живий список (все ще оновлюється, якщо DOM змінюється). NodeList — неживий, якщо не поданий з childNodes
9. У чому різниця між innerText
, textContent
та innerHTML
?
Відповідь:
Властивість | Що робить | Включає теги? | Виконує скрипти? |
---|---|---|---|
textContent | Вся текстова інформація | ❌ | ❌ |
innerText | Те, що бачить користувач (враховує CSS) | ❌ | ❌ |
innerHTML | HTML-вміст | ✅ | ❌ |
⚠️ Небезпека XSS при використанні innerHTML
з несанітайзованими даними.
10. Яка різниця між властивістю (property
) і атрибутом (attribute
) у DOM?
Атрибут — це значення, яке задається у HTML (<input value="123">
), а властивість — це значення, яке зберігається в об’єкті DOM-елемента (input.value
).
🔁 Вони синхронізуються тільки при створенні елемента, але потім змінюються незалежно. Напртклад:
<input id="test" value="hello">
const input = document.getElementById("test");
input.value = "world"; // змінилось value, але атрибут у HTML все ще "hello"
input.getAttribute("value"); // "hello"
input.setAttribute("value", "test"); // змінює саме атрибут
11. У чому різниця між event.target
і event.currentTarget
?
Відповідь:
Ці два властивості дуже важливі при роботі з подіями:
event.currentTarget
— елемент, на якому спрацював обробник
event.target
— елемент, на якому сталася подія
<div id="parent">
<button id="child">Натисни мене</button>
</div>
document.getElementById("parent").addEventListener("click", function (event) {
console.log("target:", event.target);
console.log("currentTarget:", event.currentTarget);
});
✅ Якщо натиснути кнопку, event.target
буде #child
, а event.currentTarget
— #parent
, бо саме на #parent
ми повісили слухача.
12. Що таке Event Propagation? Які в нього фази?
Event Propagation — це процес проходження події через DOM, що має три фази:
Bubbling phase (знизу вгору): подія “вспливає” назад до window
Capturing phase (зверху вниз): подія йде від window
до цільового елемента
Target phase: подія доходить до елемента, на якому вона відбулась
element.addEventListener("click", handler, useCapture);
useCapture = false
(за замовчуванням) → обробник спрацює під час bubbling
useCapture = true
→ обробник спрацює під час capturing
13. Як працює Event Bubbling (вспливання подій)? І навіщо воно потрібно?
Event Bubbling — це коли подія після цільового елемента “вспливає” вгору по DOM дереву, і кожен предок теж отримує шанс її обробити.
<div id="outer">
<button id="inner">Click me</button>
</div>
outer.addEventListener("click", () => console.log("outer"));
inner.addEventListener("click", () => console.log("inner"));
✅ Клік на кнопку → спочатку виведеться "inner"
, потім "outer"
— це приклад вспливання.
Навіщо це?
- Для делегування подій (дивись нижче)
- Для глобального відстеження
- Можна зупинити вспливання, якщо не хочемо, щоб подія доходила до батьків: event.stopPropagation();
14. Що таке Event Delegation і як його правильно реалізувати?
Event Delegation — це техніка, коли ми додаємо один обробник подій на спільного предка кількох елементів, а не на кожен елемент окремо.
🔧 Наприклад, у списку з 1000 кнопок замість того, щоб додавати 1000 слухачів, ми додаємо один:
<ul id="list">
<li>Елемент 1</li>
<li>Елемент 2</li>
...
</ul>
document.getElementById("list").addEventListener("click", function (event) {
if (event.target.tagName === "LI") {
alert(`Натиснули на: ${event.target.textContent}`);
}
});
📌 Тут event.target
— це li
, а слухач висить на ul
.
Переваги delegation:
- Менше слухачів → менше пам’яті
- Можна обробляти динамічно створені елементи
- Краще для продуктивності при великій кількості елементів
15. Що таке once: true
і навіщо це використовують у addEventListener
?
Це опція, яку можна передати при додаванні слухача, і вона означає, що обробник спрацює один раз, після чого автоматично видалиться:
button.addEventListener("click", () => {
alert("Цей алерт з’явиться тільки один раз");
}, { once: true });
📌 Це дуже зручно для:
- Початкових ініціалізацій
- Кроків в онбордингу
- Одноразових реакцій на дії користувача
16. Як повісити обробник одразу на кілька елементів?
За допомогою forEach
або for
:
document.querySelectorAll(".btn").forEach(btn =>
btn.addEventListener("click", handler)
);
❗ Але якщо таких елементів багато і вони динамічно додаються — краще використовувати Event Delegation (як вище).
17. Що таке DOM? Як він пов’язаний з HTML і CSS?
DOM (Document Object Model) — це програмний інтерфейс для HTML і XML документів, який представляє структуру документа у вигляді дерева об’єктів. Кожен елемент HTML (наприклад, <div>
, <p>
, <span>
) стає вузлом (node) у цьому дереві. DOM дозволяє JavaScript динамічно змінювати вміст, структуру та стилі документа.
DOM також включає події, які дозволяють реагувати на дії користувача (натискання миші, введення тексту тощо).
DOM пов’язаний з HTML через парсинг: браузер перетворює HTML-код у DOM-дерево.
CSS використовує DOM для застосування стилів до елементів через селектори.
18. Як додавати, видаляти та змінювати елементи в DOM?
Для маніпуляцій з DOM використовуються такі методи:
classList.add()
/ classList.remove()
— додає або видаляє класи.
Додавання елементів:
createElement(tagName)
— створює новий елемент.
appendChild(node)
/ append(node)
— додає елемент в кінець дочірніх.
insertBefore(newNode, referenceNode)
— вставляє елемент перед вказаним.
Видалення елементів:
removeChild(node)
— видаляє дочірній елемент.
remove()
— видаляє елемент з DOM.
Зміна елементів:
innerHTML
/ textContent
— змінює вміст елемента.
setAttribute(name, value)
— додає або змінює атрибут.
19. Як працює рендеринг DOM? Які методи оптимізації ви знаєте?
Рендеринг DOM — це процес відображення HTML, CSS і JavaScript на екрані. Він включає кілька етапів:
- Парсинг HTML і побудова DOM-дерева.
- Парсинг CSS і побудова CSSOM (CSS Object Model).
- Об’єднання DOM і CSSOM у Render Tree.
- Layout (розміщення елементів на сторінці).
- Paint (відображення пікселів на екрані).
Оптимізація:
- Використовуйте
DocumentFragment
для додавання великої кількості елементів. - Уникайте “layout thrashing” (часті зміни геометрії елементів).
- Використовуйте
requestAnimationFrame
для анімацій. - Мінімізуйте кількість рефлоу (reflow) і репейнт (repaint).
Приклад:
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
fragment.appendChild(div);
}
document.body.appendChild(fragment);
20. При завантаженні сторінки браузер що робить, покроково
При завантаженні веб-сторінки браузер виконує складний багатокроковий процес. Ось детальний покроковий опис того, що відбувається:
1. Введення URL
- Користувач вводить URL у адресному рядку браузера або натискає на посилання.
2. DNS-запит
- Браузер звертається до DNS-сервера для визначення IP-адреси, пов’язаної з введеним доменним ім’ям (наприклад,
example.com
).
3. Встановлення TCP-з’єднання
- Браузер використовує протокол TCP/IP для встановлення з’єднання з сервером.
- Якщо сайт використовує HTTPS, браузер також проходить процес TLS/SSL-шифрування для безпечного з’єднання.
4. Відправлення HTTP-запиту
- Браузер відправляє HTTP-запит на сервер, який включає метод запиту (GET, POST тощо) і запитуваний ресурс (наприклад, HTML-файл).
5. Отримання відповіді від сервера
- Сервер відповідає HTTP-відповіддю, яка містить статусний код (наприклад,
200 OK
) і запитаний контент (HTML-документ).
6. Парсинг HTML
- Браузер починає обробляти HTML-документ по черзі.
- При зустрічі посилань на інші ресурси (CSS, JS, зображення) браузер виконує додаткові запити для їх завантаження.
7. Побудова DOM-дерева
- HTML-документ перетворюється у Document Object Model (DOM) — дерево вузлів.
8. Парсинг CSS і побудова CSSOM
- CSS-файли та стилі обробляються для створення CSS Object Model (CSSOM), яка визначає стилі всіх елементів.
9. Побудова Render Tree
- DOM і CSSOM об’єднуються для створення Render Tree, яка описує, які елементи сторінки мають бути відображені і як вони виглядають.
10. Візуалізація (Layout і Painting)
- Вираховуються позиції та розміри елементів (Layout).
- Елементи “малюються” (Painting) на екран відповідно до стилів та позицій.
11. Виконання JavaScript
- JavaScript файли виконуються. Це може впливати на DOM і змінювати контент сторінки в реальному часі.
12. Рендеринг і оптимізація
- Після виконання всіх кроків браузер продовжує оптимізувати відображення сторінки, наприклад, за допомогою технік Lazy Loading.
13. Кешування
- Браузер зберігає статичний контент (зображення, CSS, JS) в кеш для швидшого повторного завантаження сторінки.
Цей процес працює у фоновому режимі і зазвичай відбувається дуже швидко, забезпечуючи користувачеві плавний досвід. Якщо є потреба розглянути якийсь із кроків більш детально, дайте знати — я поясню! 🚀
Обхід DOM (DOM Traversal)
Це частина, яка часто забувається на співбесідах, але дуже цінується на senior рівні — вміння ефективно знаходити елементи в DOM без querySelectorAll
, з використанням “відносних” властивостей.
21. Яка різниця між childNodes
і children
?
Властивість | Що повертає | Тип колекції |
---|---|---|
children | тільки елементи (елемент вузли) | HTMLCollection |
childNodes | усі вузли (елементи, текст, коментарі…) | NodeList |
<div id="test">
Привіт
<span>Світ</span>
</div>
const el = document.getElementById("test");
console.log(el.childNodes); // [#text, <span>]
console.log(el.children); // [<span>]
⚠️ В реальному проєкті childNodes
часто містить пробіли або \n
— бо браузер бачить і їх як текст.
22. Що таке closest()
і чим воно відрізняється від parentElement
?
closest(selector)
— шукає найближчого предка (включно із самим елементом), який відповідає CSS-селектору.
📌 Відмінність від parentElement
:
parentElement
просто повертає одного батькаclosest()
може піднятися вгору хоч доhtml
, поки не знайде селектор
23. Як перевірити, чи один елемент містить інший у DOM?
Є кілька способів:
node.contains(otherNode)
— повертає true
, якщо node
є предком otherNode
.
if (parent.contains(child)) {
console.log("child inside parent");
}
compareDocumentPosition()
— метод, що повертає бітову маску для порівняння позицій двох вузлів:
if (parent.compareDocumentPosition(child) & Node.DOCUMENT_POSITION_CONTAINED_BY) {
console.log("child всередині parent");
}
Цей метод дає набагато більше гнучкості, але в 90% випадків достатньо contains()
.
25. Як пройтись по всіх нащадках вузла рекурсивно?
Використовуємо рекурсію:
function walk(node) {
console.log(node.nodeName);
node = node.firstChild;
while (node) {
walk(node);
node = node.nextSibling;
}
}
walk(document.body);
🧠 Це базовий шаблон для обходу DOM-дерева, корисний у складних UI-фреймворках або в тестуванні.
26. Як дізнатись глибину вкладеності елемента в DOM?
Можна підніматись вгору по дереву через parentNode
або parentElement
і рахувати кроки, поки не дійдемо до document
:
function getDomDepth(el) {
let depth = 0;
while (el.parentElement) {
depth++;
el = el.parentElement;
}
return depth;
}
const element = document.querySelector(".some-class");
console.log(getDomDepth(element)); // Наприклад: 4
🔍 Це може бути корисно для:
- створення динамічних індексів елементів
- аналітики DOM-структури
- побудови outline-структури документа
27. Як перевірити, чи два елементи знаходяться в одному дереві (тобто чи мають спільного предка)?
Найпростіший варіант — використовувати compareDocumentPosition()
:
const relation = node1.compareDocumentPosition(node2);
const areInSameTree = !(relation & Node.DOCUMENT_POSITION_DISCONNECTED);
Або вручну, перевіряючи contains() в обидва боки:
if (node1.contains(node2) || node2.contains(node1)) {
console.log("В одному дереві");
}
📌 compareDocumentPosition()
також може вказати, чи node2
раніше або пізніше node1
в порядку документу, що корисно для сортування.
28. Як працює метод element.matches(selector)
і де він застосовується?
matches(selector)
— перевіряє, чи елемент відповідає CSS-селектору. Повертає true
або false
.
const el = document.querySelector("li");
if (el.matches(".active.highlighted")) {
// якщо елемент має обидва класи — виконається
}
Найчастіше використовується разом із Event Delegation, щоб перевірити, чи саме event.target
відповідає певному селектору.
list.addEventListener("click", (e) => {
if (e.target.matches("li.item")) {
e.target.classList.toggle("selected");
}
});
✅ Також корисно при створенні власних UI-компонентів або при фільтрації елементів.
29. Якими способами можна обійти DOM? Які є навігаційні властивості?
DOM Traversal — це процес переміщення по вузлах DOM (вгору, вниз, вбік) для доступу до потрібного елементу.
Найважливіші навігаційні властивості:
🔼 Вгору (до батьків):
parentNode
– найближчий батько (може бути елемент або document)parentElement
– те саме, але тільки якщо батько є елементом (тобто не#document
)
🔽 До дітей:
children
– HTMLCollection дочірніх елементів (без текстових вузлів)childNodes
– NodeList всіх дочірніх вузлів (включаючи текст, коментарі)firstElementChild
/lastElementChild
– перший / останній елемент-дитинаfirstChild
/lastChild
– перший / останній будь-який вузол
↔️ До сусідів:
previousSibling
/ nextSibling
– будь-які сусідні вузли
previousElementSibling
/ nextElementSibling
– сусідні елементи
const el = document.querySelector('.item');
const parent = el.parentElement;
const firstChild = el.firstElementChild;
const next = el.nextElementSibling;