2017-11-03 3 views
2

그림자 DOM은 <style>으로 선언 된 스타일과 동일한 범위로 스타일을로드하는 데 <link> 태그 사용을 지원합니다.이 스타일은 매우 편리하지만 스타일이 적용될 때만 적용된다는 문제가 있습니다 스타일이로드되는 동안 예를 들어 :defined pseudo selector (맞춤 선택 요소)로 방지 할 수없는 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: block !important을 사용하여 display: none;을 덮어 씁니다. style 태그에 설정된 CSS보다 구체적으로 사용하려면 !important을 사용해야합니다.

CSS를로드 한 후에 만 ​​내 요소가 표시됩니다.

또 다른 옵션으로 당신은 또한 당신의 <link> 태그 상에 onload 이벤트 핸들러를 배치 할 수 있습니다 :

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

당신이로드 된 후 바로 style 속성을 제거 할 것을 코드에 알려 것이다.

관련 문제