DOM/HTML5

Shadow DOM

AGAL 2022. 12. 9. 13:57
반응형

[출처: https://javascript.info/shadow-dom]

Shadow DOM

Shadow DOM은 캡슐화를 위해 사용됩니다. 이를 통해 구성 요소는 고유한 "섀도우" DOM ​​트리를 가질 수 있으며 기본 문서에서 실수로 액세스할 수 없으며 로컬 스타일 규칙 등을 가질 수 있습니다.

Built-in shadow DOM

복잡한 브라우저 컨트롤이 어떻게 생성되고 스타일이 지정되는지 생각해 본 적이 있습니까? (예 <input type="range">)

브라우저는 그것들을 그리기 위해 내부적으로 DOM/CSS를 사용합니다. 그 DOM 구조는 일반적으로 우리에게 숨겨져 있지만 개발자 도구에서 볼 수 있습니다. 예를 들어 Chrome에서는 개발자 도구에서 "Show user agent shadow DOM" 옵션을 활성화해야 합니다.

 

그러면 <input type="range">다음과 같이 보입니다.

위에 #shadow-root에 보이는 것을 "shadow DOM"이라고 합니다.

 

일반 JavaScript 호출 또는 선택기로 내장된 Shadow DOM 요소를 가져올 수 없습니다. 이들은 일반 자식이 아니라 강력한 캡슐화 기술입니다. 위의 예에서 유용한 속성 "pseudo"를 볼 수 있습니다. 그것은 비표준이며 역사적인 이유로 존재합니다. 다음과 같이 CSS와 함께 스타일 하위 요소를 사용할 수 있습니다.

<style>
/* make the slider track red */
input::-webkit-slider-runnable-track {
  background: red;
}
</style>

<input type="range">

Shadow tree

DOM 요소에는 두 가지 유형의 DOM 하위 트리가 있을 수 있습니다.

  • Light tree – HTML 자식으로 구성된 일반 DOM 하위 트리입니다. 이전 장에서 본 모든 하위 트리는 "가벼움"이었습니다.
  • Shadow tree – HTML에 반영되지 않은 숨겨진 DOM 하위 트리로, 엿보는 눈에서 숨겨집니다.

 

element에 둘 다 있는 경우 브라우저는 그림자 트리만 렌더링합니다. 그러나 우리는 Shadow tree와 Light tree 사이에도 일종의 구성을 설정할 수 있습니다. 구성 요소 내부를 숨기고 구성 요소 로컬 스타일을 적용하기 위해 사용자 지정 요소에서 Shadow tree를 사용할 수 있습니다.



예를 들어 이 <show-hello> 요소는 Shadow tree에서 내부 DOM을 숨깁니다.

<script>
customElements.define('show-hello', class extends HTMLElement {
  connectedCallback() {
    const shadow = this.attachShadow({mode: 'open'});
    shadow.innerHTML = `<p>
      Hello, ${this.getAttribute('name')}
    </p>`;
  }
});
</script>

<show-hello name="John"></show-hello>

이것이 Chrome 개발 도구에서 DOM이 보이는 방식이며 모든 콘텐츠는 "#shadow-root" 아래에 있습니다.

먼저 elem.attachShadow({mode: …})를 호출하면 섀도우 트리가 생성됩니다. 두 가지 제한 사항이 있습니다.

  1. 하나의 element 는 하나의 섀도우 루트만 만들 수 있습니다.
  2. 'elem'은 사용자 정의 요소이거나 “article”, “aside”, “blockquote”, “body”, “div”, “footer”, “h1…h6”, “header”, “main” “nav”, “p”, “section”, or “span” 이며, <img>와 같은 다른 요소는 Shadow tree를 호스트할 수 없습니다.

 

'mode' 옵션은 캡슐화 수준을 설정합니다. 다음 두 값 중 하나를 가져야 합니다.

  • "open" – Shadow root를 elem.shadowRoot로 사용할 수 있습니다.
    모든 코드는 요소의 섀도우 트리에 액세스할 수 있습니다.
  • "closed" – elem.shadowRoot는 항상 null입니다.

 

우리는 attachShadow에 의해 반환된 참조에 의해서만 Shadow DOM에 액세스할 수 있습니다(아마도 클래스 내부에 숨겨져 있을 것입니다). <input type="range">와 같은 브라우저 고유의 Shadow tree는 "closed" 이며, 액세스할 방법이 없습니다.

 

attachShadow에 의해 반환되는 Shadow root는 element 와 같습니다. innerHTML 또는 DOM 메서드(예: append)를 사용하여 채울 수 있습니다. Shadow root가 있는 요소를 "Shadow tree host"라고 하며 Shadow tree host 속성으로 사용할 수 있습니다.

// {mode: "open"}으로 가정하고, 그렇지 않으면 elem.shadowRoot는 null입니다.
alert(elem.shadowRoot.host === elem); // true

Encapsulation

Shadow DOM은 기본 문서와 강력하게 구분됩니다.

  1. Shadow DOM 요소는 light DOM의 querySelector에 표시되지 않습니다. 특히, Shadow DOM 요소는 light DOM의 ID와 충돌하는 ID를 가질 수 있습니다. ID는 Shadow tree 내에서만 고유해야 합니다.
  2. Shadow DOM에는 자체 스타일시트가 있습니다. 외부 DOM의 스타일 규칙은 적용되지 않습니다.

 

예를 들어

<style>
  /* 문서 스타일은 #elem(1) 내부의 shadow tree에 적용되지 않습니다. */
  p { color: red; }
</style>

<div id="elem"></div>

<script>
  elem.attachShadow({mode: 'open'});
    // shadow tree 는 고유 스타일이 있습니다. (2)
  elem.shadowRoot.innerHTML = `
    <style> p { font-weight: bold; } </style>
    <p>Hello, John!</p>
  `;

  // <p> 는 shadow tree 내부의 쿼리에서만 볼 수 있습니다. (3)
  alert(document.querySelectorAll('p').length); // 0
  alert(elem.shadowRoot.querySelectorAll('p').length); // 1
</script>
  1. 문서의 스타일은 그림자 트리에 영향을 주지 않습니다.
  2. 하지만 내부 스타일이 작동합니다.
  3. 섀도우 트리의 요소를 가져오려면 트리 내부에서 쿼리해야 합니다.
반응형