2017-11-03 23 views
2

シャドーDOMでは、<style>と宣言されたスタイルと同じ方法でスコープされるスタイルを読み込むために<link>タグの使用がサポートされていますが、スタイルは非常に便利ですが、スタイルがロードされている間に、たとえばカスタム要素の疑似セレクタ:definedで防止できないFOUCがあります。私が遭遇したもう一つの問題は、スタイルシートがロードされて適用された後に "実際の"寸法が分かっているため、カスタム要素が構築または接続されたときにシャドールート内の要素を測定することです。 ResizeObserverは実装時に役立つでしょうか?)
誰も、これらの問題を回避するための賢明な方法を考えていますか(手動でスタイルをビルドするか、ビルドステップでスタイルをインライン化せずに)?私の心配は理にかなっていますか? <head>のブロックレンダリングで<link rel="stylesheet>が指定されているため、この機能はそれに類似しているはずです。ブロックシャドウDOMレンダリングとリンクスタイル

答えて

1

FOUCを避けたい場合は、スタイルが適用されるまで要素を非表示にする必要があります。 fetchまたはXMLHttpRequest、または<link onload=...>を使用すると、スタイルがロードされたときを知ることができます。

次元の問題については、シャドウDOMに固有のものではなく、CSSアーキテクチャの結果です。

とにかく、FOUCを避けるために要素の高さと高さを設定することをお勧めしますが、フルページの再描画やレンダリングのスピードアップを回避することもしばしばあります。

シャドーDOMでの<link rel="stylsheet">のサポートは非​​常に新しいので、すべてのブラウザで期待どおりに機能しない可能性があります。

+0

'linkElement.onload =()=> ...'を使用しています:) – olanod

0

ここにshadowDOMでコンポーネントを作成したコードがあります。簡単にするために、私はsetTimeoutを使ってCSSの長いロード時間をエミュレートしています。 1秒後にCSSに要素を適用します。

あなたが述べたように、要素はCSSが読み込まれるまで片方向に見えます。

<!DOCTYPE html> 
<html> 
    <head> 
    <meta charset="utf-8"> 
    <title>FOUC Prevention for WC</title> 
    <script> 
    var delayedStyles = document.createElement('style'); 
    delayedStyles.textContent = ` 
    :host { 
     background-color: #DEE; 
     border: 1px solid #999; 
     display: block; 
     width: 400px; 
    } 

    .innerShell { 
     display: block !important; 
    } 

    h1 { 
     color: green; 
     font: 18px/1em Tahoma; 
     padding: 3px 6px; 
    } 

    p { 
     margin: 5px 10px; 
     padding: 10px; 
    } 
    `; 
    var template = document.createElement('div'); 
    template.setAttribute('style', 'display: none;'); 
    template.className = 'innerShell'; 
    template.innerHTML = ` 
    <h1>The header</h1> 
    <p>Some body content</p> 
    `; 

    // Class for `<my-component>` 
    class MyComponent extends HTMLElement { 
     constructor() { 
     super(); 

     var sr = this.attachShadow({mode: 'open'}); 
     setTimeout(() => sr.appendChild(delayedStyles.cloneNode(true)), 1000); 


     sr.appendChild(template.cloneNode(true)); 
     } 
    } 

    // Define our web component 
    customElements.define('my-component', MyComponent); 
    </script> 
    </head> 
    <body> 
    <my-component></my-component> 
    </body> 
</html> 

はこれを行うために、私は私の影のDOMに私のトップレベルの要素のstyleタグを設定します。

<!DOCTYPE html> 
<html> 
    <head> 
    <meta charset="utf-8"> 
    <title>FOUC Prevention for WC</title> 
    <script> 
    var delayedStyles = document.createElement('style'); 
    delayedStyles.textContent = ` 
    :host { 
     background-color: #DEE; 
     border: 1px solid #999; 
     display: block; 
     width: 400px; 
    } 

    h1 { 
     color: green; 
     font: 18px/1em Tahoma; 
     padding: 3px 6px; 
    } 

    p { 
     margin: 5px 10px; 
     padding: 10px; 
    } 
    `; 
    var template = document.createElement('div'); 
    template.innerHTML = ` 
    <h1>The header</h1> 
    <p>Some body content</p> 
    `; 

    // Class for `<my-component>` 
    class MyComponent extends HTMLElement { 
     constructor() { 
     super(); 

     var sr = this.attachShadow({mode: 'open'}); 
     setTimeout(() => sr.appendChild(delayedStyles.cloneNode(true)), 1000); 


     sr.appendChild(template.cloneNode(true)); 
     } 
    } 

    // Define our web component 
    customElements.define('my-component', MyComponent); 
    </script> 
    </head> 
    <body> 
    <my-component></my-component> 
    </body> 
</html> 

はマイナーチェンジで、私たちは、CSSがロードされるまで要素を非表示にすることができます。私はそれをdisplay: none;に設定しました。これは、陰影DOMの内部内容を隠します。

1秒後に、CSSがロードされると、display: none;display: block !importantで上書きされます。 styleタグで設定したCSSを具体的にするには、!importantを使用する必要があります。

CSSが読み込まれた後でのみ、要素が表示されます。別のオプションとして

また、あなたの<link>タグのonloadイベントハンドラに置くことができます:それはロードされ、その後、ちょうどstyle属性を削除したことを、コードで、

<link rel="stylesheet" href="mystylesheet.css" onload="sheetLoaded()" onerror="sheetError()">

あなたが知っているでしょう。

関連する問題