ASP.NET Core Blazor CSS 隔離

注意

這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前版本,請參閱本文的 .NET 8 版本

作者:Dave Brock

本文說明 CSS 隔離如何將 CSS 範圍設為 Razor 元件,以簡化 CSS 且避免與其他元件或程式庫發生衝突。

將 CSS 樣式隔離至個別頁面、檢視和元件,以減少或避免:

  • 相依於可能難以維護的全域樣式。
  • 巢狀內容中的樣式衝突。

啟用 CSS 隔離

若要定義元件特定的樣式,請建立 .razor.css 檔案,其符合相同資料夾中元件的 .razor 檔案名稱。 .razor.css 檔案是限定範圍的 CSS 檔案

對於 Example.razor 檔案中的 Example 元件,請在名為 Example.razor.css 的元件旁邊建立一個檔案。 Example.razor.css 檔案必須位於與 Example 元件 (Example.razor) 相同的資料夾中。 檔案的 "Example" 基底名稱區分大小寫。

Example.razor

@page "/example"

<h1>Scoped CSS Example</h1>

Example.razor.css

h1 { 
    color: brown;
    font-family: Tahoma, Geneva, Verdana, sans-serif;
}

Example.razor.css 中定義的樣式只會套用至 Example 元件的轉譯輸出。 CSS 隔離會套用至相符 Razor 檔案中的 HTML 元素。 應用程式中定義於別處的任何 h1 CSS 宣告不會與 Example 元件的樣式發生衝突。

注意

為了在統合發生時保證樣式隔離,不支援在 Razor 程式碼區塊中匯入 CSS。

CSS 隔離統合

在建置時會發生 CSS 隔離。 Blazor 會重寫 CSS 選取器,以符合元件所轉譯的標記。 重寫的 CSS 樣式會組合並產生為靜態資產。 樣式表會在 <head> 標籤 (<head> 內容的位置)內參考。 根據預設,下列 <link> 元素會新增至從 Blazor 專案範本建立的應用程式,其中預留位置 {ASSEMBLY NAME} 是專案的組件名稱:

<link href="{ASSEMBLY NAME}.styles.css" rel="stylesheet">

下列範例來自裝載的 Blazor WebAssemblyClient 應用程式。 應用程式的組件名稱為 BlazorSample.Client,而 <link> 是使用 Hosted 選項 (使用 .NET CLI 的 -ho|--hosted 選項,或或使用 Visual Studio 的 [已裝載 ASP.NET Core] 核取方塊) 建立專案時由 Blazor WebAssembly 專案範本所新增:

<link href="BlazorSample.Client.styles.css" rel="stylesheet">

在配套的檔案中,每個元件都會與範圍識別碼相關聯。 針對每個有樣式的元件,HTML 屬性會附加格式 b-{STRING},其中 {STRING} 預留位置是架構所產生的十個字元字串。 識別碼對於每個應用程式而言都是唯一的。 在轉譯的 Counter 元件中,Blazor 將範圍識別碼附加至 h1 元素:

<h1 b-3xxtam6d07>

{ASSEMBLY NAME}.styles.css 檔案會使用範圍識別碼,將樣式宣告與其元件分組。 下列範例提供上述 <h1> 元素的樣式:

/* /Components/Pages/Counter.razor.rz.scp.css */
h1[b-3xxtam6d07] {
    color: brown;
}

在建置階段,會使用慣例 obj/{CONFIGURATION}/{TARGET FRAMEWORK}/scopedcss/projectbundle/{ASSEMBLY NAME}.bundle.scp.css 建立專案配套,其中預留位置為:

  • {CONFIGURATION}:應用程式的組建組態(例如 DebugRelease)。
  • {TARGET FRAMEWORK}:目標架構 (例如 net6.0)。
  • {ASSEMBLY NAME}:應用程式的組件名稱 (例如 BlazorSample)。

子系元件支援

根據預設,CSS 隔離僅適用於您與格式 {COMPONENT NAME}.razor.css 相關聯的元件,其中預留位置 {COMPONENT NAME} 通常是元件名稱。 若要將變更套用至子系元件,請在父代元件的 .razor.css 檔案中使用任何後代元素的::deep虛擬元素::deep 虛擬元素選取的元素是元素生成範圍識別碼的「後代」

下列範例顯示名為 Parent 的父代元件,其子系元件稱為 Child

Parent.razor

@page "/parent"

<div>
    <h1>Parent component</h1>

    <Child />
</div>

Child.razor

<h1>Child Component</h1>

使用 ::deep 虛擬元素來更新 Parent.razor.css 中的 h1 宣告,以表示 h1 樣式宣告必須套用至父代元件及其子系。

Parent.razor.css

::deep h1 { 
    color: red;
}

h1 樣式現在適用於 ParentChild 元件,而不需要為子系元件建立個別的限定範圍 CSS 檔案。

::deep 虛擬元素只適用於後代元素。 下列標記會如預期般將 h1 樣式套用至元件。 父代元件的範圍識別碼會套用至 div 元素,因此瀏覽器知道要繼承父代元件的樣式。

Parent.razor

<div>
    <h1>Parent</h1>

    <Child />
</div>

不過,排除 div 元素會移除後代關聯性。 在下列範例中,樣式不會套用至子系元件。

Parent.razor

<h1>Parent</h1>

<Child />

::deep 虛擬元素會影響範圍屬性套用至規則的位置。 當您在限定範圍的 CSS 檔案中定義 CSS 規則時,範圍預設會套用至最右邊的元件。 例如:div > a 會轉換成 div > a[b-{STRING}],其中 {STRING} 預留位置是架構所產生的十個字元字串 (例如 b-3xxtam6d07)。 如果您想要將規則套用至不同的選取器,::deep 虛擬元素可讓您這麼做。 例如,div ::deep > a 會轉換成 div[b-{STRING}] > a (例如 div[b-3xxtam6d07] > a)。

::deep 虛擬元素附加至任何 HTML 元素的功能,可讓您建立限定範圍的 CSS 樣式,以在您可判斷已轉譯 HTML 標籤的結構時影響其他元件所轉譯的元素。 對於轉譯另一個元件內的超連結標記 (<a>) 的元件,請確定此元件已包裝在 div (或任何其他元素) 中,並使用 ::deep > a 規則來建立樣式,而該樣式只會在父代元件轉譯時套用至該元件。

重要

限定範圍的 CSS 僅適用於 HTML 元素,不適用於 Razor 元件或標籤協助程式,包括已套用標籤協助程式的元素,例如 <input asp-for="..." />

CSS 前置處理器支援

CSS 前置處理器可用來利用變數、巢狀、模組、混合和繼承等功能來改善 CSS 開發。 雖然 CSS 隔離原生不支援 Sass 或 Less 等 CSS 前置處理器,但只要 Blazor 在建置程序期間重寫 CSS 選取器之前進行前置處理器編譯,整合 CSS 前置處理器就會很順暢。 例如,使用 Visual Studio,在 Visual Studio 工作執行器總管中將現有的前置處理器編譯設定為 [建置之前] 工作。

許多第三方 NuGet 套件 (例如 AspNetCore.SassCompiler) 可以在 CSS 隔離發生之前,先在建置程序開始時編譯 SASS/SCSS 檔案。

CSS 隔離設定

CSS 隔離的設計訴求是要現成可用,但會提供某些進階案例的組態,例如當現有工具或工作流程有相依性時。

自訂範圍識別碼格式

根據預設,範圍識別碼會使用 b-{STRING} 格式,其中 {STRING} 預留位置是架構所產生的十個字元字串。 若要自訂範圍識別碼格式,請將專案檔更新為所需的模式:

<ItemGroup>
  <None Update="Components/Pages/Example.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

在上述範例中,針對 Example.razor.css 產生的 CSS 會將其範圍識別碼從 b-{STRING} 變更為 custom-scope-identifier

使用範圍識別碼來達到限定範圍 CSS 檔案的繼承。 在下列專案檔範例中,BaseComponent.razor.css 檔案包含跨元件的通用樣式。 DerivedComponent.razor.css 檔案會繼承這些樣式。

<ItemGroup>
  <None Update="Components/Pages/BaseComponent.razor.css" CssScope="custom-scope-identifier" />
  <None Update="Components/Pages/DerivedComponent.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

使用萬用字元 (*) 運算子,跨多個檔案共用範圍識別碼:

<ItemGroup>
  <None Update="Components/Pages/*.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

根據預設,範圍識別碼會使用 b-{STRING} 格式,其中 {STRING} 預留位置是架構所產生的十個字元字串。 若要自訂範圍識別碼格式,請將專案檔更新為所需的模式:

<ItemGroup>
  <None Update="Pages/Example.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

在上述範例中,針對 Example.razor.css 產生的 CSS 會將其範圍識別碼從 b-{STRING} 變更為 custom-scope-identifier

使用範圍識別碼來達到限定範圍 CSS 檔案的繼承。 在下列專案檔範例中,BaseComponent.razor.css 檔案包含跨元件的通用樣式。 DerivedComponent.razor.css 檔案會繼承這些樣式。

<ItemGroup>
  <None Update="Pages/BaseComponent.razor.css" CssScope="custom-scope-identifier" />
  <None Update="Pages/DerivedComponent.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

使用萬用字元 (*) 運算子,跨多個檔案共用範圍識別碼:

<ItemGroup>
  <None Update="Pages/*.razor.css" CssScope="custom-scope-identifier" />
</ItemGroup>

變更靜態 Web 資產的基底路徑

scoped.styles.css 檔案會在應用程式的根目錄產生。 在專案檔中,使用 <StaticWebAssetBasePath> 屬性來變更預設路徑。 下列範例會 scoped.styles.css 檔案和應用程式的其餘資產放在 _content 路徑上:

<PropertyGroup>
  <StaticWebAssetBasePath>_content/$(PackageId)</StaticWebAssetBasePath>
</PropertyGroup>

停用自動組合

若要退出 Blazor 在執行階段發佈及載入限定範圍檔案的方式,請使用 DisableScopedCssBundling 屬性。 使用此屬性時,這表示其他工具或程序會負責從 obj 目錄取得隔離的 CSS 檔案,並在執行階段將其發佈及載入:

<PropertyGroup>
  <DisableScopedCssBundling>true</DisableScopedCssBundling>
</PropertyGroup>

停用 CSS 隔離

在應用程式的專案檔中將 <ScopedCssEnabled> 屬性設定為 false,以停用專案的 CSS 隔離:

<ScopedCssEnabled>false</ScopedCssEnabled>

Razor 類別庫 (RCL) 支援

NuGet 套件或 Razor 類別庫 (RCL) 中元件的隔離樣式會自動組合:

  • 應用程式會使用 CSS 匯入來參考 RCL 的配套樣式。 針對名為 ClassLib 的類別庫,以及具有 BlazorSample.styles.css 樣式表的 Blazor 應用程式,RCL 的樣式表會在應用程式的樣式表頂端匯入:

    @import '_content/ClassLib/ClassLib.bundle.scp.css';
    
  • RCL 的配套樣式不會發佈為取用樣式的應用程式靜態 Web 資產。

如需有關 RCL 的詳細資訊,請參閱下列文件: