【JavaScript】ライトDOM / シャドウDOMとは

HTML5 プロフェッショナル認定試験の学習をしていると
`シャドウDOM` `ライトDOM`というワードが出てきました。

なんとも厨二臭い名前に目を引かれ、
今回はこれらについて調べてみました。


# シャドウDOMとは
MDNには下記のように記載されています。

> カスタム要素の重要な側面の一つがカプセル化です。なぜなら、カスタム要素は定義上、再利用可能な機能の一部であり、任意のウェブページにドロップして動作させることが期待されるからです。そのため、ページで実行されるコードが、内部実装を変更することでカスタム要素を誤って壊すことがないようにすることが重要です。シャドウ DOM を使用すると、DOM ツリーを要素に割り当て、ページで実行される JavaScript や CSS からこのツリーの内部を隠すことができます。

上記のようなDOMを `シャドウDOM` と呼び、
通常のDOMを `ライトDOM` と呼ぶようです。

<br />

シャドウDOMは、通常のDOMツリー内の要素に非表示のDOMツリーを紐づけます。
シャドウDOMツリーはシャドウルートから始まり、
その下に通常のDOMと同様に任意の要素を紐づけることができます。

シャドウDOMとなった要素は外部からの変更や、取得されることはありません。

下記の画像は[MDN](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM)から抜粋したものです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3669971/674f17c9-b7db-e52a-5eff-33a00e14a366.png" width="600">

ではどのように使用するのでしょうか？

# シャドウDOMの使い方
シャドウDOMを使用するには、
任意の要素に対して `attachShadow`メソッドを使用します。

`attachShadow`メソッド設定する`mode`プロパティには下記の意味があります。
-  `open` ：このシャドウルートの要素はルート外のJavaScriptからアクセスすることができる
-  `close` ：シャドウツリー内のノードはルート外のJavaScriptからアクセスすることができない


## 記述例

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Shadow DOM Example</title>
</head>
<body>
  <custom-button></custom-button>

  <script>
    // カスタム要素の定義
    class CustomButton extends HTMLElement {
      constructor() {
        super();

        // シャドウDOMをアタッチ
        const shadow = this.attachShadow({ mode: 'open' });

        // ボタン要素を作成
        const button = document.createElement('button');
        button.textContent = 'Click Me';

        // シャドウDOM内のスタイルを定義
        const style = document.createElement('style');
        style.textContent = `
          button {
            background-color: #6200ea;
            color: white;
            border: none;
            border-radius: 4px;
            padding: 10px 20px;
            cursor: pointer;
            font-size: 16px;
          }
          button:hover {
            background-color: #3700b3;
          }
        `;

        // スタイルとボタンをシャドウDOMに追加
        shadow.appendChild(style);
        shadow.appendChild(button);
      }
    }

    // カスタム要素を登録
    customElements.define('custom-button', CustomButton);
  </script>
</body>
</html>
```

# シャドウDOMの特徴とメリット
シャドウDOMには下記のような特徴とメリットがあります。
## 特徴
### カプセル化
シャドウDOMの最も重要な特徴。
これにより、コンポーネントの内部構造、スタイル、及び動作を外部から隠蔽し、分離することができます。

### スコープ付きCSS
シャドウDOM内で定義されたスタイルは、そのシャドウDOM内でのみ適用され、外部のスタイルとの競合を防ぎます。

## メリット
### 再利用性の向上
カプセル化により、コンポーネントを他のプロジェクトやページで簡単に再利用できます。

### スタイルの競合防止
シャドウDOM内のスタイルは外部に影響を与えず、また外部のスタイルからも影響を受けにくくなります。
これにより、大規模プロジェクトでのCSS管理が容易になります。

### パフォーマンスの最適化
独立したコンポーネントにより、ブラウザはレンダリングと再描画を最適化でき、パフォーマンス向上の可能性があります。

### DOMのカプセル化
シャドウDOM内の要素は、外部のJavaScriptから直接アクセスできないため、DOM操作の影響を局所化できます。

# おわりに
ReactやVueなどを使用せずに標準技術でこれらの特徴を実装できるのかと驚きました。

セマンティックなタグを自作できるのはいいなと思ったので、
またどこかのタイミングで使用したいと思います。

それでは。


# 参考文献
https://developer.mozilla.org/ja/docs/Web/API/Web_components/Using_shadow_DOM

https://qiita.com/tanimoto-hikari/items/8f56ee7d2166fe561fc6

https://qiita.com/alangdm/items/cec32f21151a9da3c3f2

https://qiita.com/KokiSakano/items/21e511313e64e70c2221

https://www.mitsue.co.jp/knowledge/blog/frontend/202012/18_0900.html