W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
shadow DOM 可以包含 ?<style>
? 和 ?<link rel="stylesheet" href="…">
? 標(biāo)簽。在后一種情況下,樣式表是 HTTP 緩存的,因此不會(huì)為使用同一模板的多個(gè)組件重新下載樣式表。
一般來說,局部樣式只在 shadow 樹內(nèi)起作用,文檔樣式在 shadow 樹外起作用。但也有少數(shù)例外。
:host
選擇器允許選擇 shadow 宿主(包含 shadow 樹的元素)。
例如,我們正在創(chuàng)建 <custom-dialog>
元素,并且想使它居中。為此,我們需要對(duì) <custom-dialog>
元素本身設(shè)置樣式。
這正是 :host
所能做的:
<template id="tmpl">
<style>
/* 這些樣式將從內(nèi)部應(yīng)用到 custom-dialog 元素上 */
:host {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
display: inline-block;
border: 1px solid red;
padding: 10px;
}
</style>
<slot></slot>
</template>
<script>
customElements.define('custom-dialog', class extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'}).append(tmpl.content.cloneNode(true));
}
});
</script>
<custom-dialog>
Hello!
</custom-dialog>
shadow 宿主( <custom-dialog>
本身)駐留在 light DOM 中,因此它受到文檔 CSS 規(guī)則的影響。
如果在局部的 :host
和文檔中都給一個(gè)屬性設(shè)置樣式,那么文檔樣式優(yōu)先。
例如,如果在文檔中我們有如下樣式:
<style>
custom-dialog {
padding: 0;
}
</style>
……那么 <custom-dialog>
將沒有 padding。
這是非常有利的,因?yàn)槲覀兛梢栽谄?nbsp;:host
規(guī)則中設(shè)置 “默認(rèn)” 組件樣式,然后在文檔中輕松地覆蓋它們。
唯一的例外是當(dāng)局部屬性被標(biāo)記 !important
時(shí),對(duì)于這樣的屬性,局部樣式優(yōu)先。
與 :host
相同,但僅在 shadow 宿主與 selector
匹配時(shí)才應(yīng)用樣式。
例如,我們希望僅當(dāng) <custom-dialog>
具有 centered
屬性時(shí)才將其居中:
<template id="tmpl">
<style>
:host([centered]) {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-color: blue;
}
:host {
display: inline-block;
border: 1px solid red;
padding: 10px;
}
</style>
<slot></slot>
</template>
<script>
customElements.define('custom-dialog', class extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'}).append(tmpl.content.cloneNode(true));
}
});
</script>
<custom-dialog centered>
Centered!
</custom-dialog>
<custom-dialog>
Not centered.
</custom-dialog>
現(xiàn)在附加的居中樣式只應(yīng)用于第一個(gè)對(duì)話框:<custom-dialog centered>
。
與 :host
相同,但僅當(dāng)外部文檔中的 shadow 宿主或它的任何祖先節(jié)點(diǎn)與 selector
匹配時(shí)才應(yīng)用樣式。
例如,:host-context(.dark-theme)
只有在 <custom-dialog>
或者 <custom-dialog>
的任何祖先節(jié)點(diǎn)上有 dark-theme
類時(shí)才匹配:
<body class="dark-theme">
<!--
:host-context(.dark-theme) 只應(yīng)用于 .dark-theme 內(nèi)部的 custom-dialog
-->
<custom-dialog>...</custom-dialog>
</body>
總之,我們可以使用 :host
-family 系列的選擇器來對(duì)組件的主元素進(jìn)行樣式設(shè)置,具體取決于上下文。這些樣式(除 !important
外)可以被文檔樣式覆蓋。
現(xiàn)在讓我們考慮有插槽的情況。
占槽元素來自 light DOM,所以它們使用文檔樣式。局部樣式不會(huì)影響占槽內(nèi)容。
在下面的例子中,按照文檔樣式,占槽的 <span>
是粗體,但是它不從局部樣式中獲取 background
:
<style>
span { font-weight: bold }
</style>
<user-card>
<div slot="username"><span>John Smith</span></div>
</user-card>
<script>
customElements.define('user-card', class extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = `
<style>
span { background: red; }
</style>
Name: <slot name="username"></slot>
`;
}
});
</script>
結(jié)果是粗體,但不是紅色。
如果我們想要在我們的組件中設(shè)置占槽元素的樣式,有兩種選擇。
首先,我們可以對(duì) <slot>
本身進(jìn)行樣式化,并借助 CSS 繼承:
<user-card>
<div slot="username"><span>John Smith</span></div>
</user-card>
<script>
customElements.define('user-card', class extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = `
<style>
slot[name="username"] { font-weight: bold; }
</style>
Name: <slot name="username"></slot>
`;
}
});
</script>
這里 <p>John Smith</p>
變成粗體,因?yàn)?CSS 繼承在 <slot>
和它的內(nèi)容之間有效。但是在 CSS 中,并不是所有的屬性都是繼承的。
另一個(gè)選項(xiàng)是使用 ::slotted(selector)
偽類。它根據(jù)兩個(gè)條件來匹配元素:
selector
? 匹配。在我們的例子中,::slotted(div)
正好選擇了 <div slot="username">
,但是沒有選擇它的子元素:
<user-card>
<div slot="username">
<div>John Smith</div>
</div>
</user-card>
<script>
customElements.define('user-card', class extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = `
<style>
::slotted(div) { border: 1px solid red; }
</style>
Name: <slot name="username"></slot>
`;
}
});
</script>
請(qǐng)注意,::slotted
選擇器不能用于任何插槽中更深層的內(nèi)容。下面這些選擇器是無效的:
::slotted(div span) {
/* 我們插入的 <div> 不會(huì)匹配這個(gè)選擇器 */
}
::slotted(div) p {
/* 不能進(jìn)入 light DOM 中選擇元素 */
}
此外,::sloated
只能在 CSS 中使用,不能在 querySelector
中使用。
如何在主文檔中設(shè)置組件的內(nèi)建元素的樣式?
像 :host
這樣的選擇器應(yīng)用規(guī)則到 <custom-dialog>
元素或 <user-card>
,但是如何設(shè)置在它們內(nèi)部的 shadow DOM 元素的樣式呢?
沒有選擇器可以從文檔中直接影響 shadow DOM 樣式。但是,正如我們暴露用來與組件交互的方法那樣,我們也可以暴露 CSS 變量(自定義 CSS 屬性)來對(duì)其進(jìn)行樣式設(shè)置。
自定義 CSS 屬性存在于所有層次,包括 light DOM 和 shadow DOM。
例如,在 shadow DOM 中,我們可以使用 --user-card-field-color
CSS 變量來設(shè)置字段的樣式,而外部文檔可以設(shè)置它的值:
<style>
.field {
color: var(--user-card-field-color, black);
/* 如果 --user-card-field-color 沒有被聲明過,則取值為 black */
}
</style>
<div class="field">Name: <slot name="username"></slot></div>
<div class="field">Birthday: <slot name="birthday"></slot></div>
</style>
然后,我們可以在外部文檔中為 <user-card>
聲明此屬性:
user-card {
--user-card-field-color: green;
}
自定義 CSS 屬性穿透 shadow DOM,它們?cè)谌魏蔚胤蕉伎梢?,因此?nèi)部的 .field
規(guī)則將使用它。
以下是完整的示例:
<style>
user-card {
--user-card-field-color: green;
}
</style>
<template id="tmpl">
<style>
.field {
color: var(--user-card-field-color, black);
}
</style>
<div class="field">Name: <slot name="username"></slot></div>
<div class="field">Birthday: <slot name="birthday"></slot></div>
</template>
<script>
customElements.define('user-card', class extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'});
this.shadowRoot.append(document.getElementById('tmpl').content.cloneNode(true));
}
});
</script>
<user-card>
<span slot="username">John Smith</span>
<span slot="birthday">01.01.2001</span>
</user-card>
shadow DOM 可以引入樣式,如 <style>
或 <link rel="stylesheet">
。
局部樣式可以影響:
:host
?-family 系列偽類),::slotted(selector)
? 允許選擇占槽元素本身,但不能選擇它們的子元素。文檔樣式可以影響:
當(dāng) CSS 屬性沖突時(shí),通常文檔樣式具有優(yōu)先級(jí),除非屬性被標(biāo)記為 !important
,那么局部樣式優(yōu)先。
CSS 自定義屬性穿透 shadow DOM。它們被用作 “勾子” 來設(shè)計(jì)組件的樣式:
var(--component-name-title, <default value>)
?。--component-name-title
? CSS 屬性。Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: