跳至主要內容
版本:v8

CSS Shadow Parts

CSS Shadow Parts 允許開發人員在 shadow tree 內的元素上設定 CSS 屬性的樣式。這在自訂 Ionic Framework Shadow DOM 元件時非常有用。

為什麼需要 Shadow Parts?

Ionic Framework 是一組分散式的 Web Components。Web Components 遵循 Shadow DOM 規範,以便封裝樣式和標記。

注意

Ionic Framework 元件並非全部都是 Shadow DOM 元件。如果元件是 Shadow DOM 元件,則在其元件文件的右上角會有一個徽章。Shadow DOM 元件的一個範例是按鈕元件

Shadow DOM 可用於防止樣式從元件洩漏並意外地應用於其他元素。例如,我們將 .button 類別指派給我們的 ion-button 元件。如果沒有 Shadow DOM 封裝,使用者在其自己的元素之一上設定類別 .button,則它會繼承 Ionic Framework 按鈕樣式。由於 ion-button 是 Shadow 元件,因此這不是問題。

但是,由於此封裝,樣式也無法流入 Shadow 元件的內部元素。這表示如果 Shadow 元件在其 shadow tree 內呈現元素,則無法使用 CSS 直接指定內部元素。以 ion-select 元件為例,它會呈現下列標記

<ion-select>
#shadow-root
<div class="select-text select-placeholder"></div>
<div class="select-icon"></div>
</ion-select>

佔位符文字和圖示元素位於 #shadow-root 內,這表示下列 CSS 無法用於設定佔位符的樣式

/* Does NOT work */
ion-select .select-placeholder {
color: blue;
}

那麼我們該如何解決這個問題?CSS Shadow Parts

Shadow Parts 的說明

Shadow parts 允許開發人員從 shadow tree 的外部設定該 shadow tree 內部的樣式。若要執行此操作,必須公開 part,然後可以使用 ::part 設定其樣式。

公開 part

建立 Shadow DOM 元件時,可以將 part 屬性指派給 shadow tree 內部的元素,將 part 新增至該元素。這會新增至 Ionic Framework 中的元件,並且不需要最終使用者採取任何動作。

繼續使用 ion-select 元件作為範例,標記會更新為如下所示

<ion-select>
#shadow-root
<div part="placeholder" class="select-text select-placeholder"></div>
<div part="icon" class="select-icon"></div>
</ion-select>

以上顯示了兩個 part:placeholdericon。請參閱選取文件以取得其所有 part。

公開這些 part 後,現在可以使用 ::part 直接設定元素的樣式。

::part 的運作方式

::part() 虛擬元素允許開發人員選取 shadow tree 內已透過 part 屬性公開的元素。

由於我們知道 ion-select 公開了 placeholder part 以在未選取值時設定文字的樣式,因此我們可以使用下列方式進行自訂

ion-select::part(placeholder) {
color: blue;
opacity: 1;
}

使用 ::part 設定樣式可讓變更該元素所接受的任何 CSS 屬性。

除了能夠指定 part 的目標之外,虛擬元素也可以設定樣式,而無需明確公開它們

ion-select::part(placeholder)::first-letter {
font-size: 22px;
font-weight: 500;
}

Parts 也適用於大多數虛擬類別

ion-item::part(native):hover {
color: green;
}
注意

供應商前綴虛擬元素結構性虛擬類別方面有一些已知的限制。

Ionic Framework Parts

可以在其 API 頁面上的 CSS Shadow Parts 標題下找到 Ionic Framework 元件的所有公開 part。若要檢視所有元件及其 API 頁面,請參閱元件文件

為了擁有 part,元件必須符合下列準則

  • 它是一個 Shadow DOM 元件。如果是 Scoped 或 Light DOM 元件,則可以直接指定子元素。如果元件是 Scoped 或 Shadow,則會在元件文件頁面上依其名稱列出。
  • 它包含子元素。例如,ion-card-header 是一個 Shadow 元件,但所有樣式都會套用至主機元素。由於它沒有子元素,因此不需要 part。
  • 子元素並非結構性的。在某些元件(包括 ion-title)中,子元素是結構性元素,用於定位內部元素。我們不建議自訂結構性元素,因為這可能會產生意料之外的結果。
注意

我們歡迎提出其他 part 的建議。要求 part 時,請建立一個新的 GitHub 問題,並盡可能提供更多資訊。

已知限制

瀏覽器支援

所有主要瀏覽器的最新版本都支援 CSS Shadow Parts。但是,某些較舊的版本不支援 shadow parts。請先確認瀏覽器支援符合要求,再於應用程式中實作 parts。如果需要較舊版本的瀏覽器支援,我們建議繼續使用CSS 變數來設定樣式。

供應商前綴虛擬元素

目前不支援供應商前綴

虛擬元素。例如,任何 ::-webkit-scrollbar 虛擬元素都屬於這種情況

/* Does NOT work */
my-component::part(scroll)::-webkit-scrollbar {
background: green;
}

如需詳細資訊,請參閱 GitHub 上的這個問題

結構性虛擬類別

大部分的虛擬類別都支援 parts,但是不支援結構性虛擬類別。以下是無法運作的結構性虛擬類別的範例。

/* Does NOT work */
my-component::part(container):first-child {
background: green;
}

/* Does NOT work */
my-component::part(container):last-child {
background: green;
}

鏈結 Parts

::part() 虛擬元素無法比對其他 ::part()

例如,my-component::part(button)::part(label) 不會比對任何內容。這是因為這樣做會公開超出預期的結構性資訊。

如果 <my-component> 的內部按鈕使用類似 part="label => button-label" 的方式將按鈕的內部 parts 轉發到面板自己的 part 元素對應中,則類似 my-component::part(button-label) 的選取器只會選取一個按鈕的標籤,而忽略任何其他標籤。