I fear that all those unfulfilled desires and unexpended energies in life will continue to torment me in death. I wish I could give full expression to all my desires in the world, and then die contented and hopeless. — Andrea Gide, Food for The World

Original link: javascript.info/shadow-dom

Shadow DOM gives us the ability to encapsulate. Allows a component to have its own Shadow DOM tree, which is not accidentally accessed by the main document query method, and can declare component-level local styles, etc.

Built-in shadow DOM

You might have thought that the native controls that the browser provides for us also require styling, defining behavior, and are still a bit complicated.

Here is a slider control that looks something like this:

The browser uses internal DOM/CSS to draw slider controls. The DOM structure is usually invisible to us, but we can check it out in the developer tools. In Chrome, we need to enable the developer tools’ “Show User Agent Shadow DOM” option to see these hidden structures.

With the above option enabled, we examine the element and see something like this:

The part under #shadow-root is called “shadow DOM”.

We can’t get these built-in Shadow DOM elements through regular JavaScript calls and selectors. Because they are not regular child elements, they just apply a powerful encapsulation technique.

In the previous example, we saw a pseudo property. This is an unnormalized, historically reserved property that you can use to style child elements with CSS.

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

<input type="range">
Copy the code

Again, pseudo is an unstandardized property. An experimental feature introduced early on by browser vendors for the ability to control the internal DOM structures was later retained for compatibility. The Shadow DOM standard allows us to implement the same functionality in other ways.

Next, we’ll use the SHADOW DOM standard defined in the DOM and other related specifications.

The Shadow tree

A DOM element can have two types of DOM subtrees:

  1. Light tree: A regular DOM subtree consisting of HTML child elements. Until we touch the Shadow tree, all we encounter are “Light” trees.
  2. Shadow tree: A hidden DOM subtree that is not reflected in HTML and is transparent to us.

If an element has both subtrees, the browser will only render the shadow tree. However, we can also create an element consisting of both shadow and light trees, which will be covered in a later section called Shadow DOM Slots, Composition.

Shadow trees can be used to customize elements — encapsulating internal implementations, using component-level native styles.

For example, the following

hides the internal DOM structure in the Shadow tree.

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

Use Chrome to check the DOM structure of the custom

element, all content is now under #shadow-root:

First, we created a Shadow tree using elem. AttachShadow ({mode: ‘open’}).

There are two limitations:

  1. Only one Shadow tree can be created per element, which means there is only one Shadow root.
  2. elemMust be a custom element, or one of the following: “article”, “aside”, “blockquote”, “body”, “div”, “footer”, “h1… H6 “, “Header”, “main”, “nav”, “P”, “Section” and “SPAN” Other elements, for example<img>Can’t create a shadow tree, that is, can’t host a shadow tree.

The mode option sets the encapsulation level and can be one of the following:

  • ‘open’ : you can use elem.shadowRoot to get shadow root.

    In this case, we can explicitly manipulate elem’s Shadow tree.

  • ‘close’ : As opposed to ‘open’, accessing elem. ShadowRoot returns null.

    In this case, the only place we can access the Shadow tree is by referring to the return value of the attachShadow method. The browser’s native shadow tree, such as , is closed and cannot be accessed.

The shadow root returned by the attachShadow method is similar to an element: we can fill it with innerHTML or a DOM method, such as append.

The element with shadow root is called the “shadow tree host” and can be accessed using the host attribute of shadow root:

// Assume {mode: "open"} otherwise access elem. ShadowRoot and get null
elem.shadowRoot.host === elem // true
Copy the code

encapsulation

The Shadow DOM is strictly separate from the main document:

  1. Shadow DOM elements are not accessible using the querySelector method of the Light DOM. Furthermore, the ID of a Shadow DOM element can be the same as that of an element in the main document, as long as it is unique in the Shadow tree.
  2. The Shadow DOM has its own style and external style rules do not affect it.

Such as:

<style>
/* The document style here does not affect the shadow tree (1) in #helloElem */
p {
    color: red;
}
</style>

<show-hello id="helloElem" name="World"></show-hello>

<script>
customElements.define('show-hello'.class extends HTMLElement {
    connectedCallback() {
        const shadow = this.attachShadow({ mode: 'open' })
        // Shadow tree has its own style (2)
        shadow.innerHTML = `
            <style>
                p {
                    font-weight: bold;
                }
            </style>
            <p>Hello, The ${this.getAttribute('name')}</p>
        `}})

console.log(document.querySelectorAll('p').length) / / 0 console.log(helloElem.shadowRoot.querySelectorAll('p').length) / / 1
</script> Copy the code
  1. The document style does not affect the shadow tree,
  2. Styles defined in the shadow tree only apply to styles in the shadow tree,
  3. Elements in the shadow tree are not queried in the document.

Refer to the link

  1. DOM:dom.spec.whatwg.org/#shadow-tre…
  2. Compatibility: caniuse.com/#feat=shado…
  3. Shadow DOM is also mentioned in other specifications, such asDOM ParsingDefines shadow root to exist oninnerHTMLattribute

conclusion

Shadow DOM is a way to create a component-local DOM (DOM).

  1. shadowRoot = elem.attachShadow({mode: open|closed})For:elemCreate shadow DOM. ifmode='open'If so, we can passelem.shadowRootProperty to shadow DOM.
  2. We can useinnerHTMLOr other DOM methodsshadowRoot.

Shadow DOM element:

  • It has its own id space domain,
  • JavaScript selector for the main documentquerySelector*Methods are invisible,
  • Only styles declared internally in the Shadow DOM are applied; the main document style does not apply to them.

The Shadow DOM is rendered by the browser, not by the “light DOM” (regular elements). Shadow DOM Slots, Composition shows you how to combine regular elements with Shadow DOM elements.

(after)