@@ -3,4 +3,308 @@ title: Styling
3
3
order : 5
4
4
---
5
5
6
- {% stub %}
6
+ Web Components have powerful styling capabilities which make them portable and extensible. Styles declared within the
7
+ Shadow DOM serve as a Web Component’s default styling. It’s similar to writing a user-agent stylesheet for your custom
8
+ element and it works quite similarily as well.
9
+
10
+ ## Shadow Encapsulation: Scoped Styles
11
+
12
+ Shadow DOM offers a boundary line between styles outside the tree, and styles inside the tree. Styles cannot cross
13
+ this boundary unintentionally. This is different to regular CSS where a selector can effect every element on a page.
14
+
15
+ ``` html
16
+ <style >
17
+ p {
18
+ color : deeppink ;
19
+ }
20
+ </style >
21
+
22
+ <p >This text is deeppink and not teal because it is outside of the shadow root.</p >
23
+
24
+ <fancy-p >
25
+ <template shadowroot =" open" >
26
+ <style >
27
+ p {
28
+ color : teal ;
29
+ }
30
+ </style >
31
+ <p >This text is teal and not deeppink because it is inside of the shadow root.</p >
32
+ </template >
33
+ </fancy-p >
34
+ ```
35
+
36
+ The ` <p> ` element within the shadow tree is not effected by the styles declared outside of the shadow tree.
37
+
38
+ ## Inheritance
39
+
40
+ Custom elements abide by the same rules of inheritance as other HTML elements. CSS properties whose default value is
41
+ ` inherit ` will inherit from their parent element, for example ` font-size ` , ` font-family ` , and ` color ` . This ` inherit `
42
+ property crosses the Shadow DOM boundary. [ CSS custom properties] [ ] default to ` inherit ` , so they'll cross Shadow DOM
43
+ boundaries too. Top-level elements within a shadow tree inherit properties from the custom element itself (also known
44
+ as the shadow host).
45
+
46
+ ``` html
47
+ <style >
48
+ article {
49
+ color : deeppink ;
50
+ }
51
+ </style >
52
+
53
+ <article >
54
+ <h1 >This text is deeppink.</h1 >
55
+ <article-meta >
56
+ <template shadowroot =" open" >
57
+ <style >
58
+ span {
59
+ font-style : italic ;
60
+ }
61
+ </style >
62
+ <span >By Some Person</span >
63
+ </template >
64
+ </article-meta >
65
+ </article >
66
+ ```
67
+
68
+ The ` <article-meta> ` custom element inherits its ` color ` from the ` <article> ` element where it is set to ` deeppink ` . The
69
+ ` <span> ` element within the shadow tree inherits its ` color ` from the ` <article-meta> ` custom element which means the
70
+ value will also be ` deeppink ` .
71
+
72
+ ## Styling elements outside of a shadow tree
73
+
74
+ In order to be portable, Web Components can provide default styles for the element itself (also known as the shadow host).
75
+ They can also style slotted elements with some default styles.
76
+
77
+ ### Writing default styles for the shadow host with ` :host ` and ` :host() `
78
+
79
+ There are two selectors which can be used to style the shadow host from within the shadow tree. They are the ` :host `
80
+ pseudo-class and the ` :host() ` pseudo-class function. The first will always select the shadow host. Here’s ` :host ` in
81
+ action:
82
+
83
+ ``` html
84
+ <fancy-p >
85
+ <template shadowroot =" open" >
86
+ <style >
87
+ :host {
88
+ display : inline-block ;
89
+ }
90
+ </style >
91
+ </template >
92
+ </fancy-p >
93
+ ```
94
+
95
+ The ` :host() ` selector will select the shadow host if it matches a given selector. For example, it can be used to
96
+ select for hosts that have a given attribute. While ` :host ` may apply to ` <fancy-p> ` component, ` :host([extra]) ` would
97
+ apply only to ` <fancy-p extra> ` elements:
98
+
99
+ ``` css
100
+ :host ([extra ]) {
101
+ font-style : italic ;
102
+ font-weight : bold ;
103
+ }
104
+ ```
105
+
106
+ ``` html
107
+ <fancy-p >I not am extra</fancy-p >
108
+ <fancy-p extra >I am extra</fancy-p >
109
+ ```
110
+
111
+ #### Chaining selectors after ` :host `
112
+
113
+ While the ` :host ` selector refers to the shadow host element which is outside of the shadow tree, if you chain selectors
114
+ it will select elements within the shadow tree.
115
+
116
+ ``` html
117
+ <fancy-p >
118
+ <template shadowroot =" open" >
119
+ <style >
120
+ :host > p {
121
+ color : deeppink ;
122
+ }
123
+ </style >
124
+ <p >I am deeppink.</p >
125
+ </template >
126
+ <p >I am not deeppink.</p >
127
+ </fancy-p >
128
+ ```
129
+
130
+
131
+ ### Writing default styles for slotted elements with ` ::slotted() `
132
+
133
+ The ` ::slotted() ` pseudo-element selector allows you to write default styles for slotted elements that match the given
134
+ selector. Specifying a selector can be useful for styling specific elements in particular ways.
135
+
136
+ ``` html
137
+ <fancy-elements >
138
+ <template shadowroot =" open" >
139
+ <style >
140
+ ::slotted(button ) {
141
+ color : deeppink ;
142
+ }
143
+
144
+ ::slotted(p ) {
145
+ color : teal ;
146
+ }
147
+ </style >
148
+ <slot ></slot >
149
+ </template >
150
+ <button >I am a slotted button</button >
151
+ <p >I am a slotted paragraph.</p >
152
+ </fancy-elements >
153
+ ```
154
+
155
+ If you want to target elements in specific slots you can pass an attribute selector which matches the slot:
156
+
157
+ ``` html
158
+ <fancy-article >
159
+ <template shadowroot =" open" >
160
+ <style >
161
+ ::slotted([slot = " title" ]) {
162
+ font-size : 2rem ;
163
+ }
164
+ ::slotted([slot = " subtitle" ]) {
165
+ font-size : 1.25rem ;
166
+ }
167
+ /* The following will target elements going into the unnamed slot */
168
+ ::slotted(:not ([slot ])) {
169
+ color : deeppink ;
170
+ }
171
+ </style >
172
+ <article >
173
+ <hgroup >
174
+ <slot name =" title" ></slot >
175
+ <slot name =" subtitle" ></slot >
176
+ </hgroup >
177
+ <slot ></slot >
178
+ </article >
179
+ </template >
180
+ <h1 slot =" title" >I am the title</h1 >
181
+ <p slot =" subtitle" >I am the subtitle</p >
182
+ <p >I am content.</p >
183
+ </fancy-article >
184
+ ```
185
+
186
+ You cannot chain selectors with ` ::slotted() ` , so the following will not work:
187
+
188
+ ``` css
189
+ ::slotted(h1 ) span {
190
+ color : deeppink ;
191
+ }
192
+ ```
193
+
194
+ ## Parts: styling a shadow tree from the outside
195
+
196
+ The CSS Shadow Part API allows elements within a shadow tree to be styled from outside of it. This allows Web Components
197
+ to be very extensible.
198
+
199
+ ``` css
200
+ fancy-article ::part(header ) {
201
+ display : grid ;
202
+ gap : 0.25rem ;
203
+ padding : 0.5rem ;
204
+ border-block-end : 0.125rem solid deeppink ;
205
+ }
206
+
207
+ fancy-article ::part(content ) {
208
+ display : grid ;
209
+ justify-content : start ;
210
+ gap : 0.5rem ;
211
+ }
212
+ ```
213
+
214
+ ``` html
215
+ <fancy-article >
216
+ <template shadowroot =" open" >
217
+ <article part =" article" >
218
+ <hgroup part =" header" >
219
+ <slot name =" title" ></slot >
220
+ <slot name =" subtitle" ></slot >
221
+ </hgroup >
222
+ <div part =" content" >
223
+ <slot name =" content" ></slot >
224
+ </div >
225
+ </article >
226
+ </template >
227
+ <h1 slot =" title" >Hello, World!</h1 >
228
+ <p slot =" subtitle" >I am a subtitle...</p >
229
+ <p >I am content</p >
230
+ </fancy-article >
231
+ ```
232
+
233
+ Similar to ` ::slotted() ` , you cannot chain selectors after ` ::part() ` to select children or siblings. The following will
234
+ not work:
235
+
236
+ ``` css
237
+ fancy-article ::part(header ) slot {
238
+ display : block ;
239
+ }
240
+ ```
241
+
242
+ ## How to include default styles for a Web Component
243
+
244
+ There are a variety of methods to include styles for a Web Component. Some will be familiar, but others are newer.
245
+
246
+ ### Using ` <style> `
247
+
248
+ The ` <style> ` tag is the most simple way to write styles for a Web Component. Just include it in your shadow tree:
249
+
250
+ ``` html
251
+ <style >
252
+ :host {
253
+ color : deeppink ;
254
+ }
255
+ </style >
256
+ ```
257
+
258
+ ### Using ` <link rel="stylesheet"> `
259
+
260
+ Using a ` <link rel="stylesheet"> ` element in the shadow tree will allow you to write styles in an external stylesheet.
261
+
262
+ ``` html
263
+ <link rel =" stylesheet" href =" /fancy-article-element.css" >
264
+ ```
265
+
266
+ If you do this, the stylesheet will be loaded after the script is loaded. This will likely cause a “flash of unstyled
267
+ content” (FOUC). To circumvent this, you can preload the stylesheet like this:
268
+
269
+ ``` html
270
+ <link rel =" preload" href =" /fancy-article-element.css" as =" style" >
271
+ ```
272
+
273
+ ### Using Constructable Stylesheets
274
+
275
+ Constructable Stylesheets are stylesheets which are programmatically created in JavaScript. You can create a new
276
+ stylesheet using the ` CSSStyleSheet ` constructor and set styles with the ` .replaceSync() ` method:
277
+
278
+ ``` js
279
+ const stylesheet = new CSSStyleSheet ()
280
+
281
+ stylesheet .replaceSync (`
282
+ :host {
283
+ color: deeppink;
284
+ }
285
+ ` )
286
+
287
+ class FancyArticleElement extends HTMLElement {
288
+ connectedCallback () {
289
+ this .attachShadow ({mode: ' open' }).adoptedStyleSheets = [stylesheet]
290
+ }
291
+ }
292
+ ```
293
+
294
+ ### Using CSS Module scripts
295
+
296
+ CSS Module scripts allow developers to import stylesheets as if they were a module script. To do so, use an import
297
+ assertion where the ` type ` is ` css ` and then you can add the imported stylesheet to the ` adoptedStyleSheets ` array for
298
+ the element’s shadow root.
299
+
300
+ ``` js
301
+ import stylesheet from ' ./fancy-article-element.css' assert { type : 'css ' }
302
+
303
+ class FancyArticleElement extends HTMLElement {
304
+ connectedCallback () {
305
+ this .attachShadow ({mode: ' open' }).adoptedStyleSheets = [stylesheet]
306
+ }
307
+ }
308
+ ```
309
+
310
+ [ CSS custom properties ] : https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties
0 commit comments