공유 스타일 시트를 사용하여 웹 구성 요소 스타일 지정
게시 됨: 2022-03-10웹 구성 요소는 개발자가 고유한 사용자 정의 HTML 요소를 정의할 수 있도록 하는 웹의 놀라운 새 기능입니다. 스타일 가이드와 결합하면 웹 구성 요소가 구성 요소 API를 생성할 수 있으므로 개발자가 코드 조각 복사 및 붙여넣기를 중단하고 대신 DOM 요소만 사용할 수 있습니다. shadow DOM을 사용하여 웹 구성 요소를 캡슐화할 수 있으며 페이지의 다른 스타일 시트와의 특정성 전쟁에 대해 걱정할 필요가 없습니다.
그러나 웹 구성 요소와 스타일 가이드는 현재 서로 모순되는 것 같습니다. 한편으로 스타일 가이드는 페이지에 전체적으로 적용되고 웹사이트 전체에서 일관성을 보장하는 일련의 규칙과 스타일을 제공합니다. 반면에 shadow DOM이 있는 웹 구성 요소는 전역 스타일이 캡슐화에 침투하는 것을 방지하므로 스타일 가이드가 영향을 미치는 것을 방지합니다.
SmashingMag에 대한 추가 정보:
- 구성 요소 기반 시스템에서 모범 사례 시행
- 더 똑똑한 스타일 시트를 위해 LESS CSS 전처리기를 사용하는 방법
- Adobe Edge Reflow에 대한 심층 분석
그렇다면 Shadow DOM이 있는 웹 구성 요소에도 일관성과 스타일을 계속 제공하는 전역 스타일 가이드와 함께 어떻게 두 가지가 공존할 수 있습니까? 고맙게도 현재 작동하는 솔루션이 있으며 글로벌 스타일 가이드가 웹 구성 요소에 스타일을 제공할 수 있도록 하는 더 많은 솔루션이 제공될 예정입니다. (이 기사의 나머지 부분에서는 "웹 구성 요소"라는 용어를 사용하여 shadow DOM이 있는 사용자 지정 요소를 나타냅니다.)
웹 구성 요소에서 전역 스타일 가이드 스타일은 무엇이어야 합니까?
웹 컴포넌트의 스타일을 지정하기 위한 전역 스타일 가이드를 얻는 방법을 논의하기 전에 스타일을 지정해야 하는 것과 하지 말아야 하는 것에 대해 논의해야 합니다.
우선, 웹 구성 요소에 대한 현재 모범 사례에서는 스타일을 포함한 웹 구성 요소를 캡슐화해야 외부 리소스가 작동하지 않도록 해야 한다고 명시하고 있습니다. 이를 통해 스타일 가이드를 사용할 수 없는 경우에도 웹사이트 안팎에서 사용할 수 있습니다.
다음은 모든 스타일을 캡슐화하는 간단한 로그인 양식 웹 구성 요소입니다.
<template> <style> :host { color: #333333; font: 16px Arial, sans-serif; } p { margin: 0; } p + p { margin-top: 20px; } a { color: #1f66e5; } label { display: block; margin-bottom: 5px; } input[type="text"], input[type="password"] { background-color: #eaeaea; border: 1px solid grey; border-radius: 4px; box-sizing: border-box; color: inherit; font: inherit; padding: 10px 10px; width: 100%; } input[type="submit"] { font: 16px/1.6 Arial, sans-serif; color: white; background: cornflowerblue; border: 1px solid #1f66e5; border-radius: 4px; padding: 10px 10px; width: 100%; } .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <div class="container"> <form action="#"> <p> <label for="username">User Name</label> <input type="text" name="username"> </p> <p> <label for="password">Password</label> <input type="password" name="password"> </p> <p> <input type="submit" value="Login"> </p> <p class="footnote">Not registered? <a href="#">Create an account</a></p> </form> </div> </template> <script> const doc = (document._currentScript || document.currentScript).ownerDocument; const template = doc.querySelector('#login-form-template'); customElements.define('login-form', class extends HTMLElement { constructor() { super(); const root = this.attachShadow({mode: 'closed'}); const temp = document.importNode(template.content, true); root.appendChild(temp); } }); </script>
참고: 코드 예제는 웹 구성 요소에 대한 버전 1 사양에 작성되었습니다.
그러나 모든 웹 구성 요소를 완전히 캡슐화하면 특히 기본 요소의 타이포그래피 및 스타일 설정과 관련하여 많은 중복 CSS가 불가피하게 발생합니다. 개발자가 웹 구성 요소에서 단락, 앵커 태그 또는 입력 필드를 사용하려는 경우 웹사이트의 나머지 부분처럼 스타일이 지정되어야 합니다.
웹 구성 요소에 필요한 모든 스타일을 완전히 캡슐화하면 단락, 앵커 태그, 입력 필드 등의 스타일을 지정하기 위한 CSS가 이를 사용하는 모든 웹 구성 요소에 복제됩니다. 이렇게 하면 유지 관리 비용이 증가할 뿐만 아니라 사용자의 다운로드 크기가 훨씬 더 커집니다.
모든 스타일을 캡슐화하는 대신 웹 구성 요소는 고유한 스타일만 캡슐화한 다음 공유 스타일 집합에 의존하여 다른 모든 스타일을 처리해야 합니다. 이러한 공유 스타일은 본질적으로 일종의 Normalize.css가 되어 웹 구성 요소가 스타일 가이드에 따라 기본 요소의 스타일이 지정되도록 할 수 있습니다.
이전 예에서 로그인 양식 웹 구성 요소는 .container
및 .footnote
라는 두 가지 고유 클래스에 대해서만 스타일을 선언합니다. 나머지 스타일은 공유 스타일 시트에 속하며 단락, 앵커 태그, 입력 필드 등의 스타일을 지정합니다.
요컨대, 스타일 가이드는 웹 구성 요소의 스타일을 지정하려고 해서는 안 되며 대신 웹 구성 요소가 일관된 모양을 달성하는 데 사용할 수 있는 공유 스타일 집합을 제공해야 합니다.
외부 스타일 시트로 Shadow DOM을 스타일링하는 방법
웹 구성 요소에 대한 초기 사양(버전 0으로 알려짐)은 외부 스타일 시트가 ::shadow
또는 /deep/
CSS 선택기를 사용하여 shadow DOM에 침투할 수 있도록 허용했습니다. ::shadow
및 /deep/
를 사용하면 웹 구성 요소가 원하든 원하지 않든 스타일 가이드가 shadow DOM을 관통하고 공유 스타일을 설정할 수 있습니다.
/* Style all p tags inside a web components shadow DOM */ login-form::shadow p { color: red; }
최신 버전의 웹 구성 요소 사양(버전 1으로 알려짐)의 출현으로 작성자는 외부 스타일 시트가 shadow DOM에 침투하는 기능을 제거했으며 대안을 제공하지 않았습니다. 대신, 철학은 드래곤을 사용하여 웹 구성 요소의 스타일을 지정하는 것에서 대신 브리지를 사용하는 것으로 변경되었습니다. 즉, 웹 구성 요소 작성자는 강제로 허용하는 것이 아니라 구성 요소에 스타일을 지정할 수 있는 외부 스타일 규칙을 책임져야 합니다.
불행히도, 그 철학은 아직 웹을 따라잡지 못했고, 이는 우리를 약간의 난관에 빠뜨렸습니다. 운 좋게도 현재 사용 가능한 몇 가지 솔루션과 멀지 않은 미래에 제공될 일부 솔루션을 사용하면 공유 스타일 시트에서 웹 구성 요소의 스타일을 지정할 수 있습니다.
오늘 할 수 있는 일
웹 구성 요소가 스타일을 공유할 수 있도록 하는 세 가지 기술이 있습니다. @import
, 사용자 정의 요소 및 웹 구성 요소 라이브러리입니다.
@import 사용
오늘날 스타일 시트를 웹 구성 요소로 가져오는 유일한 기본 방법은 @import
를 사용하는 것입니다. 이것이 작동하더라도 안티 패턴입니다. 그러나 웹 구성 요소의 경우 훨씬 더 큰 성능 문제입니다.
<template> <style> @import "styleguide.css" </style> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- rest of template DOM --> </template>
일반적으로 @import
는 모든 스타일 시트를 병렬이 아닌 직렬로 다운로드하므로 특히 중첩된 경우 안티 패턴입니다. 우리 상황에서는 하나의 스타일 시트를 연속으로 다운로드하는 것은 도움이 되지 않으므로 이론상으로는 괜찮을 것입니다. 그러나 Chrome에서 이것을 테스트했을 때 결과에 따르면 @import
를 사용하면 웹 구성 요소에 스타일을 직접 포함할 때보다 페이지 렌더링이 최대 0.5초 더 느려집니다.
참고: HTML 가져오기의 폴리필이 기본 HTML 가져오기와 비교하여 작동하는 방식의 차이로 인해 WebPagetest.org는 HTML 가져오기를 기본적으로 지원하는 브라우저(예: Chrome)에서만 안정적인 결과를 제공하는 데 사용할 수 있습니다.
결국 @import
는 여전히 안티 패턴이며 웹 구성 요소에서 성능 문제가 될 수 있습니다. 따라서 이것은 훌륭한 솔루션이 아닙니다.
Shadow DOM을 사용하지 마십시오
웹 구성 요소에 공유 스타일을 제공하려는 문제는 shadow DOM을 사용하는 데서 발생하기 때문에 문제를 완전히 피하는 한 가지 방법은 shadow DOM을 사용하지 않는 것입니다.
Shadow DOM을 사용하지 않음으로써 웹 구성 요소 대신 사용자 정의 요소를 생성하게 됩니다(아래 옆 참조). 유일한 차이점은 shadow DOM과 범위 지정이 없다는 것입니다. 귀하의 요소는 페이지 스타일의 영향을 받지만 오늘 이미 처리해야 하므로 처리 방법을 아직 모르는 것은 아닙니다. 사용자 정의 요소는 브라우저 지원이 뛰어난 webcomponentjs 폴리필에서 완벽하게 지원됩니다.
커스텀 엘리먼트의 가장 큰 장점은 바로 지금 바로 패턴 라이브러리를 생성할 수 있고, 스타일 공유 문제가 해결될 때까지 기다릴 필요가 없다는 점입니다. 그리고 웹 구성 요소와 사용자 정의 요소의 유일한 차이점은 shadow DOM이기 때문에 공유 스타일에 대한 솔루션을 사용할 수 있게 되면 사용자 정의 요소에서 항상 shadow DOM을 활성화할 수 있습니다.
사용자 정의 요소를 생성하기로 결정했다면 사용자 정의 요소와 웹 구성 요소 간의 몇 가지 차이점을 알고 있어야 합니다.
첫째, 사용자 정의 요소의 스타일은 페이지 스타일의 영향을 받으며 그 반대의 경우도 마찬가지이므로 선택기가 충돌을 일으키지 않도록 해야 합니다. 페이지에서 이미 스타일 가이드를 사용하는 경우 사용자 정의 요소에 대한 스타일을 스타일 가이드에 그대로 두고 요소가 예상 DOM 및 클래스 구조를 출력하도록 합니다.
스타일 가이드에 스타일을 남겨두면 개발자가 이전처럼 스타일 가이드를 계속 사용할 수 있지만 가능하면 새 사용자 지정 요소를 사용하도록 천천히 마이그레이션할 수 있기 때문에 개발자를 위한 원활한 마이그레이션 경로를 만들 수 있습니다. 모든 사람이 사용자 정의 요소를 사용하면 스타일을 요소 내부에 이동하여 함께 유지하고 나중에 웹 구성 요소로 쉽게 리팩토링할 수 있습니다.
둘째, IFFE(즉시 호출된 함수 표현식) 내부에 모든 JavaScript 코드를 캡슐화하여 전역 범위로 변수를 블리드하지 않도록 합니다. CSS 범위 지정을 제공하지 않는 것 외에도 사용자 정의 요소는 JavaScript 범위 지정을 제공하지 않습니다.
셋째, 템플릿 DOM을 요소에 추가하려면 사용자 정의 요소의 connectedCallback
함수를 사용해야 합니다. 웹 구성 요소 사양에 따르면 사용자 정의 요소는 생성자 함수 중에 자식을 추가해서는 안 되므로 connectedCallback
함수에 DOM 추가를 연기해야 합니다.
마지막으로 <slot>
요소는 shadow DOM 외부에서 작동하지 않습니다. 즉, 개발자가 자신의 콘텐츠를 사용자 정의 요소에 삽입할 수 있는 방법을 제공하려면 다른 방법을 사용해야 합니다. 일반적으로 이것은 DOM을 직접 조작하여 원하는 곳에 컨텐츠를 삽입하는 것을 수반합니다.
그러나 사용자 정의 요소가 있는 shadow DOM과 light DOM 사이에 분리가 없기 때문에 요소의 계단식 스타일로 인해 삽입된 DOM의 스타일을 지정하지 않도록 매우 주의해야 합니다.
<!-- login-form.html --> <template> <style> login-form .container { max-width: 300px; padding: 50px; border: 1px solid grey; } login-form .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template> <script> (function() { const doc = (document._currentScript || document.currentScript).ownerDocument; const template = doc.querySelector('#login-form-template'); customElements.define('login-form', class extends HTMLElement { constructor() { super(); } // Without the shadow DOM, we have to manipulate the custom element // after it has been inserted in the DOM. connectedCallback() { const temp = document.importNode(template.content, true); this.appendChild(temp); } }); })(); </script>
<!-- index.html --> <link rel="stylesheet" href="styleguide.css"> <link rel="import" href="login-form.html"> <login-form></login-form>
성능 면에서 사용자 정의 요소는 사용되지 않는 웹 구성 요소만큼 빠릅니다(예: 공유 스타일 시트를 head
에 연결하고 기본 DOM 요소만 사용). 오늘날 사용할 수 있는 모든 기술 중에서 이것이 가장 빠릅니다.
제쳐두고: 사용자 정의 요소는 여전히 모든 의도와 목적을 위한 웹 구성 요소입니다. "웹 구성 요소"라는 용어는 사용자 정의 요소, 템플릿 태그, HTML 가져오기 및 그림자 DOM의 네 가지 개별 기술을 설명하는 데 사용됩니다.
불행히도 이 용어는 네 가지 기술의 조합을 사용하는 모든 것을 설명하는 데 사용되었습니다. 이것은 사람들이 "웹 구성 요소"라고 말할 때 무엇을 의미하는지에 대해 많은 혼란을 야기했습니다. Rob Dodson이 발견한 것처럼 Shadow DOM이 있거나 없는 사용자 정의 요소에 대해 이야기할 때 다른 용어를 사용하는 것이 도움이 된다는 것을 알게 되었습니다.
내가 이야기한 대부분의 개발자는 "웹 구성 요소"라는 용어를 shadow DOM을 사용하는 사용자 정의 요소와 연관시키는 경향이 있습니다. 따라서 이 기사의 목적을 위해 웹 구성 요소와 사용자 정의 요소를 인위적으로 구분했습니다.
웹 구성 요소 라이브러리 사용
오늘날 사용할 수 있는 또 다른 솔루션은 Polymer, SkateJS 또는 X-Tag와 같은 웹 구성 요소 라이브러리입니다. 이러한 라이브러리는 오늘날 지원의 허점을 채우는 데 도움이 되며 웹 구성 요소를 만드는 데 필요한 코드를 단순화할 수도 있습니다. 또한 일반적으로 웹 구성 요소를 더 쉽게 작성할 수 있는 추가 기능을 제공합니다.
예를 들어 Polymer를 사용하면 몇 줄의 JavaScript로 간단한 웹 구성 요소를 만들 수 있습니다. 추가 이점은 Polymer가 shadow DOM 및 공유 스타일 시트를 사용하기 위한 솔루션을 제공한다는 것입니다. 즉, 지금 스타일을 공유하는 웹 구성 요소를 만들 수 있습니다.
이렇게 하려면 모든 공유 스타일을 포함하는 스타일 모듈이라고 하는 것을 만듭니다. 공유 스타일이 인라인된 <style>
태그이거나 공유 스타일 시트를 가리키는 <link rel=“import”>
태그일 수 있습니다. 두 경우 모두 <style include>
태그를 사용하여 웹 구성 요소에 스타일을 포함하면 Polymer가 스타일을 구문 분석하여 웹 구성 요소에 인라인 <style>
태그로 추가합니다.
<!-- shared-styles.html --> <dom-module> <!-- Link to a shared style sheet --> <!-- <link rel="import" href="styleguide.css"> --> <!-- Inline the shared styles --> <template> <style> :host { color: #333333; font: 16px Arial, sans-serif; } /* Rest of shared CSS */ </style> </template> </dom-module>
<!-- login-form.html --> <link rel="import" href="../polymer/polymer.html"> <link rel="import" href="../shared-styles/shared-styles.html"> <dom-module> <template> <!-- Include the shared styles --> <style include="shared-styles"></style> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template> <script> Polymer({ is: 'login-form' }); </script> </dom-module>
라이브러리 사용의 유일한 단점은 웹 구성 요소의 렌더링 시간이 지연될 수 있다는 것입니다. 라이브러리의 코드를 다운로드하고 처리하는 데 시간이 걸리기 때문에 이것은 놀라운 일이 아닙니다. 페이지의 모든 웹 구성 요소는 라이브러리 처리가 완료될 때까지 렌더링을 시작할 수 없습니다.
Polymer의 경우 기본 웹 구성 요소에 비해 페이지 렌더링 시간을 최대 0.5초까지 지연시킬 수 있습니다. 스타일을 포함하는 스타일 모듈은 스타일을 연결하는 스타일 모듈보다 약간 느리고 스타일을 웹 구성 요소에 직접 포함하는 것은 스타일 모듈을 사용하는 것만큼 빠릅니다.
다시 말하지만, Polymer는 렌더링 시간을 느리게 만들기 위해 특별히 아무 것도 하지 않습니다. Polymer 라이브러리를 다운로드하고 모든 멋진 기능을 처리하고 모든 템플릿 바인딩을 만드는 데 시간이 걸립니다. 웹 구성 요소 라이브러리를 사용하기 위해 수행해야 하는 절충안일 뿐입니다.
성능 테스트 결과에 따르면 Polymer를 사용하면 웹 구성 요소가 기본 웹 구성 요소보다 최대 0.5초 느리게 렌더링됩니다.
미래의 약속
현재 솔루션 중 어느 것도 효과가 없더라도 절망하지 마십시오. 모든 것이 순조롭게 진행된다면 몇 개월에서 몇 년 이내에 몇 가지 다른 접근 방식을 사용하여 공유 스타일을 사용할 수 있을 것입니다.
사용자 정의 속성
사용자 정의 속성(또는 CSS 변수라고도 함)은 CSS에서 변수를 설정하고 사용하는 방법입니다. 이 개념은 CSS 전처리기에 새로운 것은 아니지만 기본 CSS 기능으로서 사용자 정의 속성은 실제로 전처리기 변수보다 더 강력합니다.
사용자 정의 속성을 선언하려면 –my-variable: value
의 사용자 정의 속성 표기법을 사용하고 property: var(–my-variable)
를 사용하여 변수에 액세스합니다. 사용자 정의 속성은 다른 CSS 규칙과 마찬가지로 계단식이므로 해당 값은 상위 항목에서 상속되고 재정의될 수 있습니다. 사용자 정의 속성에 대한 유일한 주의 사항은 선택기 내부에서 선언해야 하며 전처리기 변수와 달리 자체적으로 선언할 수 없다는 것입니다.
<style> /* Declare the custom property */ html { --main-bg-color: red; } /* Use the custom property */ input { background: var(--main-bg-color); } </style>
사용자 정의 속성을 매우 강력하게 만드는 한 가지는 shadow DOM을 관통하는 기능입니다. 이것은 /deep/
및 ::shadow
선택자와 같은 개념이 아닙니다. 웹 구성 요소에 강제로 들어가지 않기 때문입니다. 대신 웹 구성 요소의 작성자는 CSS의 사용자 정의 속성을 사용해야 적용됩니다. 즉, 웹 구성 요소 작성자는 웹 구성 요소의 소비자가 자신의 스타일을 적용하는 데 사용할 수 있는 사용자 지정 속성 API를 만들 수 있습니다.
<template> <style> /* Declare the custom property API */ :host { --main-bg-color: brown; } .one { color: var(--main-bg-color); } </style> <div class="one">Hello World</div> </template> <script> /* Code to set up my-element web component */ </script> <my-element></my-element> <style> /* Override the custom variable with own value */ my-element { --main-bg-color: red; } </style>
사용자 정의 속성에 대한 브라우저 지원은 놀라울 정도로 훌륭합니다. 이것이 오늘날 사용할 수 있는 솔루션이 아닌 유일한 이유는 Custom Elements 버전 1 없이는 작동하는 폴리필이 없기 때문입니다. webcomponentjs 폴리필을 지원하는 팀은 현재 이를 추가하기 위해 노력하고 있지만 아직 출시되지 않았으며 빌드된 상태입니다. 즉, 프로덕션을 위해 자산을 해시하면 사용할 수 없습니다. 제가 알기로는 내년 초에 출시될 예정입니다.
그럼에도 불구하고 사용자 정의 속성은 웹 구성 요소 간에 스타일을 공유하는 좋은 방법이 아닙니다. 단일 속성 값을 선언하는 데만 사용할 수 있기 때문에 웹 구성 요소는 스타일 가이드의 모든 스타일을 포함해야 하지만 값이 변수로 대체됩니다.
사용자 정의 속성은 공유 스타일보다 테마 옵션에 더 적합합니다. 이 때문에 사용자 정의 속성은 우리 문제에 대한 실행 가능한 솔루션이 아닙니다.
/* 사용자 정의 속성 사용 */ input { background: var(–main-bg-color); } </스타일>
사용자 정의 속성을 매우 강력하게 만드는 한 가지는 shadow DOM을 관통하는 기능입니다. 이것은 /deep/
및 ::shadow
선택자와 같은 개념이 아닙니다. 웹 구성 요소에 강제로 들어가지 않기 때문입니다. 대신 웹 구성 요소의 작성자는 CSS의 사용자 정의 속성을 사용해야 적용됩니다. 즉, 웹 구성 요소 작성자는 웹 구성 요소의 소비자가 자신의 스타일을 적용하는 데 사용할 수 있는 사용자 지정 속성 API를 만들 수 있습니다.
<template> <style> /* Declare the custom property API */ :host { --main-bg-color: brown; } .one { color: var(--main-bg-color); } </style> <div class="one">Hello World</div> </template> <script> /* Code to set up my-element web component */ </script> <my-element></my-element> <style> /* Override the custom variable with own value */ my-element { --main-bg-color: red; } </style>
사용자 정의 속성에 대한 브라우저 지원은 놀라울 정도로 훌륭합니다. 이것이 오늘날 사용할 수 있는 솔루션이 아닌 유일한 이유는 Custom Elements 버전 1 없이는 작동하는 폴리필이 없기 때문입니다. webcomponentjs 폴리필을 지원하는 팀은 현재 이를 추가하기 위해 노력하고 있지만 아직 출시되지 않았으며 빌드된 상태입니다. 즉, 프로덕션을 위해 자산을 해시하면 사용할 수 없습니다. 제가 알기로는 내년 초에 출시될 예정입니다.
그럼에도 불구하고 사용자 정의 속성은 웹 구성 요소 간에 스타일을 공유하는 좋은 방법이 아닙니다. 단일 속성 값을 선언하는 데만 사용할 수 있기 때문에 웹 구성 요소는 스타일 가이드의 모든 스타일을 포함해야 하지만 값이 변수로 대체됩니다.
사용자 정의 속성은 공유 스타일보다 테마 옵션에 더 적합합니다. 이 때문에 사용자 정의 속성은 우리 문제에 대한 실행 가능한 솔루션이 아닙니다.
@적용 규칙
사용자 정의 속성 외에도 CSS는 @apply
규칙도 가져옵니다. 적용 규칙은 본질적으로 CSS 세계를 위한 믹스인입니다. 사용자 지정 속성과 유사한 방식으로 선언되지만 속성 값 대신 속성 그룹을 선언하는 데 사용할 수 있습니다. 사용자 정의 속성과 마찬가지로 해당 값을 상속 및 재정의할 수 있으며 작동하려면 선택기 내부에서 선언해야 합니다.
<style> /* Declare rule */ html { --typography: { font: 16px Arial, sans-serif; color: #333333; } } /* Use rule */ input { @apply --typography; } </style>
@apply
규칙에 대한 브라우저 지원은 기본적으로 존재하지 않습니다. Chrome은 현재 기능 플래그 뒤에서 지원하지만(찾을 수 없음) 그게 전부입니다. 사용자 정의 속성에 대한 폴리필이 없는 것과 같은 이유로 작동하는 폴리필도 없습니다. webcomponentjs 폴리필 팀은 사용자 정의 속성과 함께 @apply
규칙을 추가하기 위해 노력하고 있으므로 새 버전이 출시되면 둘 다 사용할 수 있습니다.
사용자 정의 속성과 달리 @apply
규칙은 스타일 공유에 훨씬 더 나은 솔루션입니다. 속성 선언 그룹을 설정할 수 있으므로 이를 사용하여 모든 기본 요소에 대한 기본 스타일을 설정한 다음 웹 구성 요소 내에서 사용할 수 있습니다. 이렇게 하려면 모든 기본 요소에 대해 @apply
규칙을 만들어야 합니다.
그러나 스타일을 사용하려면 각 기본 요소에 수동으로 스타일을 적용해야 합니다. 그러면 여전히 모든 웹 구성 요소에서 스타일 선언이 복제됩니다. 모든 스타일을 포함하는 것보다 낫지만 모든 웹 구성 요소의 맨 위에 상용구가 되기 때문에 그다지 편리하지도 않습니다. 스타일이 제대로 작동하려면 추가해야 한다는 것을 기억해야 합니다.
/* styleguide.css */ html { --typography: { color: #333333; font: 16px Arial, sans-serif; } --paragraph: { margin: 0; } --label { display: block; margin-bottom: 5px; } --input-text { background-color: #eaeaea; border: 1px solid grey; border-radius: 4px; box-sizing: border-box; color: inherit; font: inherit; padding: 10px 10px; width: 100%; } --input-submit { font: 16px/1.6 Arial, sans-serif; color: white; background: cornflowerblue; border: 1px solid #1f66e5; border-radius: 4px; padding: 10px 10px; width: 100%; } /* And so on for every native element */ }
<!-- login-form.html --> <template> <style> :host { @apply --typography; } p { @apply --paragraph; } label { @apply --label; } input-text { @apply --input-text; } .input-submit { @apply --input-submit; } .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- Rest of template DOM --> </template>
광범위한 상용구가 필요하기 때문에 @apply
규칙이 웹 구성 요소 간에 스타일을 공유하는 데 좋은 솔루션이 될 것이라고는 생각하지 않습니다. 그러나 그들은 테마를 위한 훌륭한 솔루션입니다.
Shadow DOM에서
웹 구성 요소 사양에 따르면 브라우저는 Shadow DOM의 모든 <link rel=“stylesheet”>
태그를 무시하여 문서 조각 내부에서와 같이 처리합니다. 이로 인해 웹 구성 요소의 공유 스타일에 연결할 수 없었습니다. 불행히도 몇 달 전 Web Components Working Group에서 <link rel=“stylesheet”>
태그가 다음에서 작동해야 한다고 제안했습니다. 그림자 DOM. 불과 일주일 간의 토론 끝에 그들은 모두 그렇게 해야 한다는 데 동의했고 며칠 후 HTML 사양에 추가했습니다.
<template> <link rel="stylesheet" href="styleguide.css"> <style> .container { max-width: 300px; padding: 50px; border: 1px solid grey; } .footnote { text-align: center; } </style> <!-- rest of template DOM --> </template>
작업 그룹이 사양에 동의하는 것이 너무 빨리 들린다면 그것은 새로운 제안이 아니기 때문입니다. Shadow DOM에서 link
태그를 작동시키는 것은 실제로 최소 3년 전에 제안되었지만 성능에 문제가 없다는 것을 확인할 수 있을 때까지 백로그되었습니다.
제안 수락이 충분히 흥미롭지 않은 경우 Chrome 55(현재 Chrome Canary)는 link
태그가 shadow DOM에서 작동하도록 하는 초기 기능을 추가했습니다. 이 기능은 현재 버전의 Chrome에도 포함된 것 같습니다. Safari조차도 Safari 18에서 이 기능을 구현했습니다.
공유 스타일에서 링크할 수 있는 것은 웹 구성 요소 간에 스타일을 공유하는 가장 편리한 방법입니다. link
태그를 생성하기만 하면 모든 기본 요소가 추가 작업 없이 그에 따라 스타일이 지정됩니다.
물론 브라우저 제조업체가 이 기능을 구현하는 방식에 따라 이 솔루션이 실행 가능한지 여부가 결정됩니다. 이것이 제대로 작동하려면 동일한 CSS 파일을 요청하는 여러 웹 구성 요소가 하나의 HTTP 요청만 발생하도록 link
태그의 중복을 제거해야 합니다. CSS는 또한 한 번만 구문 분석되어야 하므로 웹 구성 요소의 각 인스턴스는 공유 스타일을 다시 계산할 필요가 없고 대신 계산된 스타일을 재사용합니다.
Chrome은 이미 이 두 가지를 모두 수행합니다. 따라서 다른 모든 브라우저 제조업체가 동일한 방식으로 구현한다면 shadow DOM에서 작동하는 link
태그는 웹 구성 요소 간에 스타일을 공유하는 방법의 문제를 확실히 해결할 것입니다.
구성 가능한 스타일 시트
아직 알아내지 못했기 때문에 믿기 어려울 수도 있지만 shadow DOM에서 작동하는 link
태그는 장기적인 솔루션이 아닙니다. 대신, 실제 솔루션인 구성 가능한 스타일 시트에 도달하기 위한 단기 솔루션일 뿐입니다.
구성 가능한 스타일 시트는 생성자 함수를 통해 JavaScript에서 StyleSheet
개체를 생성할 수 있도록 하는 제안입니다. 생성된 스타일 시트는 API를 통해 shadow DOM에 추가될 수 있으며, 이를 통해 shadow DOM은 공유 스타일 세트를 사용할 수 있습니다.
불행히도 이것이 내가 제안서에서 수집할 수 있는 전부입니다. Web Components Working Group에 문의하여 구성 가능한 스타일 시트에 대한 자세한 정보를 찾으려고 했지만 W3C CSS Working Group의 메일링 리스트로 리디렉션되어 다시 질문했지만 아무도 응답하지 않았습니다. 제안이 2년 넘게 업데이트되지 않았기 때문에 제안이 어떻게 진행되고 있는지조차 알 수 없었습니다.
그럼에도 불구하고 웹 구성 요소 작업 그룹은 웹 구성 요소 간에 스타일을 공유하기 위한 솔루션으로 이를 사용합니다. 제안이 업데이트되거나 웹 구성 요소 작업 그룹에서 제안 및 채택에 대한 추가 정보를 발표할 수 있기를 바랍니다. 그때까지는 "장기적" 솔루션이 가까운 장래에 일어나지 않을 것 같습니다.
교훈
몇 달 간의 연구와 테스트 끝에 저는 미래에 대해 매우 희망적입니다. 웹 구성 요소 간에 스타일을 공유할 수 있는 솔루션이 몇 년 동안 없었지만 마침내 답이 있다는 사실은 위안이 됩니다. 그 대답은 몇 년 더 동안 확립되지 않을 수 있지만 적어도 그들은 거기에 있습니다.
오늘날 공유 스타일 가이드를 사용하여 웹 구성 요소의 스타일을 지정하려면 shadow DOM을 사용하지 않고 대신 사용자 정의 요소를 생성하거나 스타일 공유를 위해 폴리필 지원을 지원하는 웹 구성 요소 라이브러리를 사용할 수 있습니다. 두 솔루션 모두 장단점이 있으므로 프로젝트에 가장 적합한 것을 사용하십시오.
웹 구성 요소에 대해 알아보기 전에 잠시 기다리기로 결정했다면 몇 년 안에 이들 간에 스타일을 공유할 수 있는 훌륭한 솔루션을 갖게 될 것입니다. 따라서 진행 상황을 계속 확인하십시오.
염두에 두어야 할 사항
오늘 사용자 정의 요소 또는 웹 구성 요소를 사용하기로 결정했다면 몇 가지 사항을 염두에 두십시오.
가장 중요한 것은 웹 구성 요소 사양이 여전히 활발히 개발되고 있다는 것입니다. 이는 상황이 바뀔 수 있고 바뀔 것임을 의미합니다. 웹 구성 요소는 여전히 최첨단 기술이므로 개발하면서 긴장을 늦추지 않도록 준비하십시오.
Shadow DOM을 사용하기로 결정했다면 폴리필 브라우저에서 매우 느리고 성능이 좋지 않다는 것을 알아두십시오. 이러한 이유로 Polymer의 개발자들은 그늘진 DOM 구현을 만들고 이를 기본값으로 설정했습니다.
Chrome, Opera 및 최근에는 Safari가 shadow DOM 버전 0을 지원하는 유일한 브라우저입니다. Firefox는 버전 29 이후 실험 뒤에서 지원했지만 여전히 개발 중입니다. Microsoft는 여전히 Edge용으로 이를 고려하고 있으며 로드맵에서 높은 우선 순위.
그러나 shadow DOM 버전 0은 이전 사양입니다. Shadow DOM 버전 1은 새로운 버전으로 Chrome, Safari, Opera에서만 완벽하게 지원합니다. 사용자 정의 요소 버전 0은 동일한 업그레이드를 거쳤으며 Chrome만 사용자 정의 요소 버전 1을 완전히 지원하는 반면 Safari 기술 미리 보기는 버전 17부터 지원합니다. 사용자 정의 요소 버전 1은 웹 구성 요소 작성 방식에 몇 가지 주요 변경 사항이 있습니다. 따라서 그것이 무엇을 수반하는지 완전히 이해하십시오.
마지막으로 webcomponentjs 폴리필은 shadow DOM 및 사용자 정의 요소의 버전 0 구현만 지원합니다. polyfill의 버전 1 분기는 버전 1을 지원하지만 아직 릴리스되지 않았습니다.