Shadow DOM е уеб стандарт, който позволява капсулиране и обхват на стилове и маркиране в конкретен компонент или елемент, като го изолира от останалата част от страницата. Той позволява създаването на многократно използвани уеб компоненти със собствено DOM дърво, CSS стилове и поведение на JavaScript. Капсулираните елементи и стилове в сенчестия DOM са скрити от основния документ, предотвратявайки намеса от външни стилове и скриптове.

т.е.: Да кажем, че създавам персонализиран компонент на бутон, наречен „my-button“. Като използвате DOM в сянка, можете да дефинирате HTML структурата на бутона, CSS стиловете и JavaScript функционалността в неговия собствен капсулиран обхват. Стиловете на компонента няма да бъдат повлияни от глобалните стилове на страницата, което гарантира последователен външен вид и поведение. След това други разработчици могат да използват вашия компонент „my-button“, без да се притесняват от конфликти с техния съществуващ CSS или JavaScript код.

export default function App() {
  useEffect(() => {
    const parentDiv = document.createElement("div");
    const shadowRoot = parentDiv.attachShadow({ mode: "open" });
    shadowRoot.innerHTML=
    `<button id="withShadow">Shadow Button</button>`;

    const buttonStyles = `
    #withShadow {
      background-color: green;
      color: yellow;
      border: none;
      cursor: pointer;
    }
  `;

  const style = document.createElement('style');
  style.textContent = buttonStyles;
  shadowRoot.appendChild(style);
  document.body.appendChild(parentDiv);
  }, []);

  return (
    <>
      <button>Normal Button </button>
    </>
  );
}

В изображението можете да видите два бутона, единият е бутон без shadow dom, а другият е с активиран shadow dom.
Приложих някакъв стил върху бутона в shadow dom, но това не оказва влияние върху стила на цялостния потребителски интерфейс.

Защо се използва Shadow DOM?

По принцип отговорът е същият като по-горе.
Shadow DOM се използва за капсулиране на стиловете, структурата и поведението на уеб компонент, като се гарантира, че той няма да пречи или да бъде засегнат от стиловете и скриптовете на околна страница. Той позволява на разработчиците да създават самостоятелни компоненти със собствено DOM дърво, CSS стилове и JavaScript логика, което ги прави многократно използвани и изолирани. Това капсулиране подобрява модулността, намалява конфликтите и подобрява поддръжката на кода, което води до по-стабилни и мащабируеми уеб приложения.

Какви са различните режими в Shadow DOM?

Има три различни режима в Shadow DOM:

  1. Отворен режим: Този режим позволява стиловете и елементите в рамките на Shadow DOM да бъдат достъпвани и манипулирани извън компонента.
  2. Затворен режим: В този режим Shadow DOM е напълно капсулиран, предотвратявайки всякакъв директен достъп или манипулиране извън компонента. Стиловете и елементите остават изолирани.
  3. Режим на сянка: Този режим е подобен на затворения режим, но също така скрива съществуването на Shadow DOM. Стиловете и елементите са скрити, осигурявайки пълно капсулиране и поверителност.

Тези режими осигуряват гъвкавост при контролиране на достъпността и видимостта на Shadow DOM, в зависимост от изискванията на уеб компонента.

Какви са предимствата на Shadow DOM?

Има много предимства от използването на shadow DOM, но ще спомена няколко, които изпитах на практика.

  1. Енкапсулиране: Shadow DOM ни позволява да капсулираме стиловете, структурата и поведението на уеб компонент, като го предпазваме от намеса или влияние от стиловете и скриптовете на околната страница.
  2. Модулност: Със Shadow DOM компонентите се превръщат в самостоятелни обекти, които могат да се използват повторно в различни части на уеб приложение, насърчавайки модулността и повторната употреба на кода.
  3. Изолация: Капсулирането, предоставено от Shadow DOM, изолира компонентите от останалата част от страницата, намалявайки конфликтите и улеснявайки управлението и поддръжката на сложни уеб приложения.
  4. Обхват на стила: Shadow DOM гарантира, че CSS стиловете, дефинирани в компонент, се прилагат само към елементите в компонента, като се избягват непреднамерени изтичания на стилове и сблъсъци с други части на страницата.
  5. Подобрена производителност: Shadow DOM оптимизира производителността на рендиране, като позволява на браузъра да прави ефективни актуализации в рамките на капсулираните компоненти, свеждайки до минимум нуждата от глобални прерисовки и преформатиране.

Как може да се използва стилизиране в Shadow DOM?

Намерих четири начина за оформяне на shadow dom.

1. Вътрешен стил:

const shadowRoot = element.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `
  <style>
    /* CSS rules specific to the Shadow DOM */
    h1 {
      color: red;
    }
  </style>
  <h1>Hello, Shadow DOM!</h1>
`; 

В този пример стиловете са дефинирани в тага <style> в Shadow DOM. Тези стилове ще се прилагат само към елементите в Shadow DOM.

2. Външни таблици със стилове:

const shadowRoot = element.attachShadow({ mode: 'open' });
const linkElem = document.createElement('link');
linkElem.setAttribute('rel', 'stylesheet');
linkElem.setAttribute('href', 'styles.css');
shadowRoot.appendChild(linkElem);
shadowRoot.innerHTML = `
  <h1>Hello, Shadow DOM!</h1>
`;

Тук външен лист със стилове (styles.css) е свързан към Shadow DOM с помощта на елемент <link>. Стиловете, дефинирани във външния стилов лист, ще бъдат приложени към елементите в рамките на Shadow DOM.

3. CSS персонализирани свойства:

const shadowRoot = element.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `
  <style>
    /* CSS rules using custom properties */
    h1 {
      color: var(--text-color, red);
    }
  </style>
  <h1>Hello, Shadow DOM!</h1>
`;

Персонализираните CSS свойства могат да се използват в рамките на Shadow DOM за дефиниране на гъвкави и тематични стилове. В този пример цветът на елемента <h1> се задава с помощта на персонализираното свойство --text-color.

4. Използване на обекта CSSStyleSheet

const shadowRoot = element.attachShadow({ mode: 'open' });

const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync(`
  h1 {
    color: red;
  }
`);

shadowRoot.adoptedStyleSheets = [stylesheet];

shadowRoot.innerHTML = `
  <h1>Hello, Shadow DOM!</h1>
`;

При този подход се създава CSSStyleSheet обект и към него се добавят стилове с помощта на метода replaceSync(). След това свойството adoptedStyleSheets на Shadow Root се използва за прилагане на листа със стилове към Shadow DOM. Стиловете, дефинирани в листа със стилове, ще бъдат приложени към елементите в рамките на Shadow DOM.

От споменатите по-горе стратегии намерих използването на обекта CSSStylesSheet за ефективно и лесно за използване.

Заключение

В заключение, Shadow DOM може да се използва за капсулиране на стиловете и маркирането на компонентите, като се гарантира, че те остават незасегнати от останалата част от страницата. Това насърчава повторното използване на кода и поддръжката чрез създаване на самостоятелни елементи. Достъпността и видимостта на капсулираното съдържание могат да се контролират с помощта на отворен, затворен или режим на сянка. Освен това Shadow DOM подобрява производителността чрез минимизиране на глобалните пребоядисвания и преформатиране, като същевременно позволява прецизен обхват на стила. Като цяло предлага ефективно решение за управление на стила на компонентите, подобряване на организацията на кода и оптимизиране на производителността на уеб приложенията.