在昨天的文章裡,我們介紹了三種從外部改變 Shadow DOM 樣式的方法。今天要繼續延伸這個主題,來看看另一種改變樣式的技巧。
還記得前兩天學過的 slot(插槽) 嗎?這次要介紹的,就是如何調整插入 slot 裡的子元素樣式。
::slotted
是一種 CSS 的偽元素選擇器,可以在元件的 Shadow DOM 中,選擇外部插入 slot 的元素。
他可以幫助我們先替外部插入的內容設定一個預設樣式,確保使用者在元件初始使用時有一致的外觀。
當你想要給使用者插入的內容一個初始統一的外觀,例如彈窗的標題、內容、按鈕區域。
適合用來提供基礎樣式
(像是間距、字體大小、顏色),而不是一個強制的設計規範。
如果 UI 是要嚴格訂定的樣式的話(例如設計系統中的標準化按鈕),那就不適合只靠 ::slotted()
。
可以使用 ::slotted([slot="名稱"])
來賦予指定 slot 的基礎樣式。
我們試著用前面建立的 custom-modal
來加入預設樣式看看!
::slotted
加入預設的樣式class CustomModal extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
const cloneNode = this.render().cloneNode(true);
shadowRoot.appendChild(cloneNode);
}
render() {
const template = document.createElement('template');
template.innerHTML = `
<style>
.modal-container {
min-width: 150px;
padding: 20px;
background-color: #dddddd;
border-radius: 6px;
}
.modal-header {
font-size: 20px;
font-weight: 500;
padding-bottom: 4px;
}
.modal-content {
padding: 4px;
border-top: 1px solid #999999;
border-bottom: 1px solid #999999;
}
::slotted([slot="header"]) {
padding: 8px;
font-size: 16px;
color: #7361de;
}
::slotted([slot="content"]) {
padding: 8px;
font-size: 12px;
color: #333173;
}
::slotted([slot="footer"]) {
display: flex;
padding: 4px;
background-color: #ffffff;
}
</style>
<div class="modal-container">
<div class="modal-header">
<slot name="header"></slot>
</div>
<div class="modal-content">
<slot name="content">
<p class="default-content">預設文字</p>
</slot>
</div>
<div class="modal-footer">
<slot name="footer"></slot>
</div>
</div>
`
return template.content;
}
}
customElements.define('custom-modal', CustomModal);
<custom-modal>
<div slot="header">
<p>插入的 header</p>
</div>
<div slot="content">彈出視窗的內容</div>
<div slot="footer">
<button>只能按確定!</button>
</div>
</custom-modal>
得到的結果:
這時你可能會想:如果我不喜歡元件的預設樣式,能不能改掉?
答案是 可以的! 只要在外部加上 class 或 inline-style,就可以輕鬆覆蓋掉原本的樣式。
index.html
<custom-modal>
<div slot="header" style="background-color: #eeeeee;">
<p>插入的 header</p>
</div>
<div slot="content" style="padding: 16px 8px">彈出視窗的內容</div>
<div slot="footer" style="padding: 12px 8px; border-radius: 6px">
<button>只能按確定!</button>
</div>
</custom-modal>
得到的結果:
以上,就是 ::slotted
的基本使用方法!
::slotted
不實用的地方::slotted
主要是讓元件能控制插槽的直接內容,而不是深入的去改外部結構。::slotted()
只能選中被插入 slot 的那個直接子元素本身,沒辦法指定哪個 slot,只能靠插進來的元素屬性(例如 [slot="title"])去區分。(你不能用 ::slotted( a > b)
直接選擇更內部的元素)。::slotted(div p){} /* 錯誤的用法 */
::slotted()
可能幫不上忙,因為外部可以簡單的就覆蓋掉。<p>
、<div>
、又或是你根本沒想過的 <table>
::slotted()
提供的預設樣式就變得沒什麼幫助。::slotted
:適合並不是嚴謹樣式的元件使用,可以替插入 slot 的元素設定基礎樣式
,且可以被外部覆蓋。::host()
:適合不希望被外部輕易修改樣式的元件使用,可以針對元件定義預設樣式(例如:primary、secondary、small...),外部透過在 host 上加 class 或屬性來改變樣式。CSS Variable
:適合讓外部定義統一規範的元件,透過可繼承的變數統一管理顏色、間距等設計樣式。::part()
:適合想開放部分樣式給外部的元件,如果希望外部可以更彈性的控制元件內部樣式,可以在元件內標記 part
,外部使用者使用 ::part()
選擇對應的元素來改變樣式。