Web_Components 系列(九)—— Shadow Host 的 CSS 選擇器

程式設計三昧發表於2022-02-16

css選擇器.001

前言

在上一節我們瞭解瞭如何給自定義元件設定樣式,當時是將自定義標籤的樣式設定在主 DOM 中的:

<style>
    my-card {
        display: block;
        margin: 20px;
        width: 200px;
        height: 200px;
        border: 3px solid #000;
    }
</style>
<my-card></my-card>

雖然實現了樣式設定的目的,但是卻存在一個弊端:自定義標籤的樣式被寫死了,不夠靈活。

如果能夠在自定義元件內部控制自定義標籤的樣式,那樣的話會相對靈活,而且也算是實現了”封裝、相互隔離“的元件原則。今天,我們就來學習一下如何在自定義元件內部實現自定義標籤的樣式控制。

在正文開始之前,我們再複習一下 Shadow DOM 的整體結構:

image-20220209182955624

Shadow DOM 的 CSS 選擇器

今天的重點是認識與 Shadow DOM 相關的幾個選擇器。

:host 偽類選擇器

選取內部使用該部分 CSS 的 Shadow host 元素,其實也就是自定義標籤元素。用法如下:

:host {
    display: block;
    margin: 20px;
    width: 200px;
    height: 200px;
    border: 3px solid #000;
}

注意::host 選擇器只在 Shadow DOM 中使用才有效果。

比如:

image-20220216185103096

另外,可以使用 :host 子選擇器 的形式來給 Shadow Host 的子元素設定樣式,比如:

image-20220216185355256

:host 偽類選擇器的相容性如下:

image-20220216191419476

:host()偽類函式

:host() 的作用是獲取給定選擇器的 Shadow Host。比如下面的程式碼:

<my-card class="my-card"></my-card>
<my-card></my-card>

<script>
    class MyCard extends HTMLElement {
        constructor () {
            super();
            this.shadow = this.attachShadow({mode: "open"});
            let styleEle = document.createElement("style");
            styleEle.textContent = `
                :host(.my-card){
                    display: block;
                    margin: 20px;
                    width: 200px;
                    height: 200px;
                    border: 3px solid #000;
                }
                :host .card-header{
                    border: 2px solid red;
                    padding:10px;
                    background-color: yellow;
                    font-size: 16px;
                    font-weight: bold;
                }
            `;
            this.shadow.appendChild(styleEle);


            let headerEle = document.createElement("div");
            headerEle.className = "card-header";
            headerEle.innerText = "My Card";
            this.shadow.appendChild(headerEle);
        }
    }

    window.customElements.define("my-card", MyCard);

</script>

:host(.my-card) 只會選擇類名為 my-card 的自定義元素, 且它後面也可以跟子選擇器來選擇自己跟節點下的子元素。

需要注意的是::host() 的引數是必傳的,否則選擇器函式失效,比如:

image-20220216192613676

:host() 偽類函式的相容性如下:

image-20220216191512610

:host-context()偽類函式

用來選擇特定祖先內部的自定義元素,祖先元素選擇器通過引數傳入。比如以下程式碼:

<div id="container">
    <my-card></my-card>
</div>
<my-card></my-card>
<script>
    class MyCard extends HTMLElement {
        constructor () {
            super();
            this.shadow = this.attachShadow({mode: "open"});
            let styleEle = document.createElement("style");
            styleEle.textContent = `
                :host-context(#container){
                    display: block;
                    margin: 20px;
                    width: 200px;
                    height: 200px;
                    border: 3px solid #000;
                }
                :host .card-header{
                    border: 2px solid red;
                    padding:10px;
                    background-color: yellow;
                    font-size: 16px;
                    font-weight: bold;
                }
            `;
            this.shadow.appendChild(styleEle);


            let headerEle = document.createElement("div");
            headerEle.className = "card-header";
            headerEle.innerText = "My Card";
            this.shadow.appendChild(headerEle);
        }
    }

    window.customElements.define("my-card", MyCard);

</script>

:host-context(#container) 只會對 id 為 container 元素下的自定義元素生效,效果如下:

image-20220216193941726

注意:這裡的引數也是必傳的,否則整個選擇器函式不生效。

其相容性如下:

image-20220216200336292

:host:host()共存的必要性

看完上面的介紹後,不少人可能會有這樣一個疑惑::host(.my-card){} 不是可以直接用 :host.my-card{} 代替?

答案是不可以!!!,因為::host.my-card 實質上的意思是找 .my-card (Shadow root)的 :host(Shadow Host) ,這 Shadow DOM 的從結構上來說就已經互相矛盾了。

總結

以上就是關於 Shadow Host 的 CSS 選擇器內容,總結一下:

  • :host 範圍最大,匹配所有的自定義元素例項;
  • :host() 只選擇自身包含特定選擇器的自定義元素;
  • :host-context() 選擇擁有特定選擇器父元素的自定義元素。

~

~ 本文完,感謝閱讀!

~

學習有趣的知識,結識有趣的朋友,塑造有趣的靈魂!

大家好,我是〖程式設計三昧〗的作者 隱逸王,我的公眾號是『程式設計三昧』,歡迎關注,希望大家多多指教!

本作品採用《CC 協議》,轉載必須註明作者和本文連結