2017-07-12 19 views
1

シャドーDOMを使用する別のカスタム要素内であってもどこでも使用できるカスタム要素(シャドーDOMなし)があります。しかし、私は両方の場所で動作するスタイルを取得する方法はわかりません。シャドーDOMの内側と外側の非シャドーDOMカスタム要素の使用

class fancyButton extends HTMLElement { 
 
    constructor() { 
 
    super(); 
 

 
    this.innerHTML = ` 
 
     <style> 
 
     fancy-button button { 
 
     padding: 10px 15px; 
 
     background: rgb(62,118,194); 
 
     color: white; 
 
     border: none; 
 
     border-radius: 4px 
 
     } 
 
     </style> 
 
     <button>Click Me</button>`; 
 
    } 
 
} 
 

 
customElements.define('fancy-button', fancyButton);
<fancy-button></fancy-button>
シャドウDOM要素内

、挿入されたスタイルタグはfancy-buttonスタイルが動作するようになります:

は例えば、私はシンプルなfancy-button要素を作成して言うことができます。ただし、このコンポーネントがシャドウDOM要素の外側で使用されると、スタイルタグは要素が使用されるたびに複製されます。

代わりに、htmlインポートファイルの一部としてスタイルタグを追加すると、スタイルはシャドーDOMの外でしか動作しませんが、少なくとも1回宣言されます。

<!-- fancy-button.html --> 
<style> 
fancy-button button { 
    padding: 10px 15px; 
    background: rgb(62,118,194); 
    color: white; 
    border: none; 
    border-radius: 4px 
} 
</style> 

<script> 
class fancyButton extends HTMLElement { 
    constructor() { 
    super(); 

    this.innerHTML = `<button>Click Me</button>`; 
    } 
} 

customElements.define('fancy-button', fancyButton); 
</script> 

シャドウDOMの内側と外側の両方で使用されるカスタム要素スタイルを追加するにはどうすればよいですか?

+1

最も効果的なのは、それが機能する唯一のソリューションだからです。別の方法は、あなたがShadow DOMにいて、必要に応じてスタイルを追加しているかどうかをテストすることです。 – Supersharp

答えて

1

私は、シャドウDOMにいるかどうかを確認するためのSupersharp提案のおかげで解決策を見つけることができました。

最初にスタイルをインポートファイルの一部として追加して、スタイルがデフォルトでシャドウDOMの外側に適用されるようにします。 DOMに要素が追加されると、getRootNode()にチェックされ、ShadowRootノードに要素が追加されているかどうかが確認されます。それがあって、スタイルがまだルートに注入されていなければ、スタイルを手動で注入することができます。

var div = document.createElement('div'); 
 
var shadow = div.attachShadow({mode: 'open'}); 
 
shadow.innerHTML = '<fancy-button></fancy-button>'; 
 

 
document.body.appendChild(div);
<style data-fs-dialog> 
 
    fancy-button button { 
 
    padding: 10px 15px; 
 
    background: rgb(62,118,194); 
 
    color: white; 
 
    border: none; 
 
    border-radius: 4px 
 
    } 
 
</style> 
 

 
<script> 
 
class fancyButton extends HTMLElement { 
 
    constructor() { 
 
    super(); 
 
    } 
 
    
 
    connectedCallback() { 
 
    this.innerHTML = `<button>Click Me</button>`; 
 
    
 
    var root = this.getRootNode(); 
 

 
    // In polyfilled browsers there is no shadow DOM so global styles still style 
 
    // the "fake" shadow DOM. We need to test for truly native support so we know 
 
    // when to inject styles into the shadow dom. The best way I've found to do that 
 
    // is to test the toString output of a shadowroot since `instanceof ShadowRoot` 
 
    // returns true when it's just a document-fragment in polyfilled browsers 
 
    if (root.toString() === '[object ShadowRoot]' && !root.querySelector('style[data-fs-dialog]')) { 
 
     var styles = document.querySelector('style[data-fs-dialog]').cloneNode(true); 
 
     root.appendChild(styles); 
 
    } 
 
    } 
 
} 
 

 
customElements.define('fancy-button', fancyButton); 
 
</script> 
 

 
<fancy-button></fancy-button>

すべてのブラウザが影DOMで<link rel=stylesheet>をサポートする場合は、その後、robdodsonが示唆したように、インラインスクリプトは、外部スタイルシートに変身することができ、そしてコードが少しクリーナーです。

1

おそらく、エレメントのJSと一緒に販売する別々のCSSファイルにスタイルを配置したいと思うでしょう。しかし、あなたが指摘したように、要素を別の要素の影DOM内に置くと、スタイルはその範囲では機能しません。このため、シャドウルートを作成してそこにスタイルをポップするのが普通です。あなたがそれをしたくない理由は何ですか?

+0

ほとんどの場合、共有できるシャドウDOMなしでカスタム要素を作成できるかどうかを確認するための深いダイビング実験です(CSS変数を必要としないスタイルオーバーライドが容易なため)。しかし、要素のスタイリングに影DOMを必要とするだけなら、それは影DOMで動作するので、非影のDOM共有要素を書きたいと思うときは不安ですが、残念です。 –

関連する問題