ShadowDOM を使う CustomElement にグローバルスタイルを適用する
CustomElement のインスタンス作成時に document.adoptedStyleSheets からグローバルスタイルを取り出して ShadowDOM の adoptedStyleSheets に追加する
注意点: document.adoptedStyleSheets の変更を検知できないので インスタンス作成後に変更できない
| foo-bar { | |
| display: block; | |
| margin: 10px; | |
| } | |
| /* not applied */ | |
| .box { | |
| color: red; | |
| } |
| <!DOCTYPE html> | |
| <script type="module"> | |
| import document_only_sheet from "./document-only-style.css" assert { type: "css" } | |
| import global_style from "./global-style.css" assert { type: "css" } | |
| import { globalStyle } from "./global-style.js" | |
| global_style.global_style = true | |
| document.adoptedStyleSheets.push(document_only_sheet, global_style) | |
| const selector = (sheets) => { | |
| return sheets.filter(x => x.global_style) | |
| } | |
| customElements.define("foo-bar", class extends globalStyle(HTMLElement, selector) { | |
| constructor() { | |
| super() | |
| this.shadowRoot.innerHTML = ` | |
| <div class="box"> | |
| text | |
| </div> | |
| ` | |
| } | |
| }) | |
| </script> | |
| <foo-bar></foo-bar> |
| .box { | |
| border: 3px solid green; | |
| padding: 10px; | |
| } |
| export const globalStyle = (Base, selector) => { | |
| return class extends Base { | |
| constructor() { | |
| super() | |
| const sheets = selector([...this.ownerDocument.adoptedStyleSheets]) | |
| const root = this.attachShadow({ mode: "open" }) | |
| root.adoptedStyleSheets.push(...sheets) | |
| } | |
| } | |
| } |