Skip to main content

Shadow DOM проти звичайного DOM

Звичайний (light) DOM, це основне дерево документа, а Shadow DOM, це вкладене ізольоване DOM-дерево всередині елемента, яке має свої стилі, розмітку й поведінку і не впливає на зовнішній документ. Простими словами: light DOM, це «поверхня сайту», а Shadow DOM, це «нутрощі компонента», сховані від решти світу.

Теорія

TL;DR

  • Light DOM, це все, що ви пишете в HTML і бачите в DevTools; Shadow DOM живе всередині host-елемента.
  • Light DOM підпорядкований глобальним CSS, Shadow DOM від них ізольований.
  • До light DOM ходять через document.querySelector(), до тіньового, тільки через shadowRoot.querySelector().
  • Слоти (<slot>) є лише в Shadow DOM: через них вміст із light DOM показується всередині компонента.
  • Shadow DOM потрібен для інкапсуляції компонентів, ізоляції стилів і самодостатніх елементів на кшталт <video>.

Швидкий приклад

javascript
const card = document.querySelector('.card'); const shadow = card.attachShadow({ mode: 'open' }); shadow.innerHTML = ` <style> button { color: blue; } </style> <button>Внутрішня</button> `;

Тепер у card є внутрішній Shadow DOM, який ізольований від зовнішніх стилів, не видно у звичайному дереві документа (а при mode: 'closed' до нього взагалі не дістатися ззовні) і який керує власними елементами. Глобальне правило button { color: red; } не перефарбує цю кнопку, бо вона живе у своєму тіньовому дереві.

Означення: light DOM і Shadow DOM

ТипЩо це таке
Звичайний (light) DOMОсновне дерево HTML-документа: усе, що ви пишете в HTML і бачите в DevTools.
Shadow DOMВкладене ізольоване DOM-дерево всередині елемента (компонента), яке має свої стилі, розмітку й поведінку і не впливає на зовнішній документ.

Для порівняння, звичайна картка в light DOM:

html
<div class="card"> <h2>Заголовок</h2> <button>Клік</button> </div>

Тут усе видно в основному DOM, кнопку можна дістати через document.querySelector('button'), а глобальні стилі впливають на все: правило button { color: red; } зробить кнопку червоною.

Ключові відмінності

ХарактеристикаЗвичайний DOM (light)Shadow DOM
Де живеУ дереві документаУсередині host-елемента
Видимість у DevToolsТакТак, але приховано за замовчуванням, вмикається опцією «Show user agent shadow DOM»
СтилізаціяПідпорядкований глобальним CSSІзольований від глобальних стилів
ІзоляціяНемає, стилі та JS впливають одне на одногоПовна, ізольований контекст
Де використовуютьБудь-який HTMLWeb Components, вбудовані елементи (<video>, <input> та інші)
ВзаємодіяПрямо через document.querySelector()Тільки через shadowRoot.querySelector()
СлотиНемаєЄ (<slot> для вставки вмісту з light DOM)

Структура і слоти

html
<body> <my-card> <!-- host-елемент --> #shadow-root (shadow DOM) <style>...</style> <button>Click</button> #light-dom (звичайний DOM) <p slot="content">...</p> </my-card> </body>

Тут my-card, це елемент-хост, #shadow-root, це його внутрішній Shadow DOM, а зовнішні елементи можуть передавати вміст усередину через <slot>. Важливо: слотований <p> фізично залишається в light DOM і підпадає під глобальні стилі, просто показується у визначеному місці тіньового дерева.

Доступ із коду

Із light DOM видно лише «оболонку» компонента:

javascript
console.log(document.querySelector('my-card').innerHTML); // Порожньо, бо нутрощі заховані в Shadow DOM

До тіньового дерева ходять лише за посиланням на корінь:

javascript
const shadow = document.querySelector('my-card').shadowRoot; console.log(shadow.querySelector('button')); // <button>Click</button>

Якщо дерево створене з mode: 'closed', shadowRoot буде null, і ззовні до внутрішніх вузлів не дістатися взагалі.

Де це потрібно на практиці

Shadow DOM беруть, коли треба:

  • інкапсулювати компонент (веб-компоненти, UI-бібліотеки);
  • ізолювати стилі, щоб глобальні CSS не ламали зовнішній вигляд;
  • зробити перевикористовуваний елемент, наприклад <custom-slider>;
  • зробити компонент самодостатнім, як <video> чи <select>.

Життєвий приклад. У звичайному DOM ви перевизначили стилі кнопок на всьому сайті, і раптом кнопки всередині компонента «поламалися», бо стилі глобальні. З Shadow DOM компонент зі своїми стилями ізольований, і жодне глобальне button { color: red } на нього не вплине.

КритерійЗвичайний DOMShadow DOM
ВидимістьДоступний усьому кодуПрихований і ізольований
СтиліСпільніІзольовані
ВикористанняПовсякденний HTMLКомпоненти і вбудовані елементи
ВзаємодіяЧерез documentЧерез shadowRoot
БезпекаІзоляції немаєЄ інкапсуляція

Типові помилки

  • Шукати внутрішні вузли компонента через document.querySelector(): селектор не перетинає межу тіньового дерева.
  • Думати, що глобальний CSS «просто спрацює» всередині компонента: туди стилі передають через власний <style>, CSS-змінні або ::part.
  • Плутати слот із перенесенням вузла: слотований вміст лишається в light DOM, а не копіюється в тіньове дерево.
  • Вважати closed захистом даних: це лише ускладнення доступу, реальної безпеки воно не дає.
  • Забувати про події: щоб подія з тіньового дерева піднялася назовні, її створюють з composed: true, і ззовні її target буде хостом.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.