有時候會想對不同 Component 做個別樣式設定,但如果把 class 都寫在 wwwroot/css/site.css,或是針對某個元素改動樣式,可能導致改一個就影響全部 Component,這種全域衝突是必須避免的,但應該怎麼做?
.NET 5 推出了 CSS isolation(CSS 隔離),建立 Component 個別 css 檔案,命名規範為 {Component name}.razor.css,檔案會自動跟 {Component name}.razor 收納在一起,且名稱不分大小寫。下圖可以看到不論是 Blog.razor.css 還是 blog.razor.css 都會跟 Blog.razor 被視為同一組。

CSS isolation 會在建置時被處理,Blazor 會改寫 CSS 選擇器並產生一個 {Project name}.style.css 檔案,可以在 wwwroot/index.html (Blazor WebAssembly) 或是 Pages/_Host.cshtml (Blazor Server) 的 <head> 標籤內找到引用路徑,由於這是建置時才會產生,所以在專案內是看不到的,我們打開瀏覽器的 Dev tool 並切換到 Sources 頁籤,就能看到這檔案。

有人可能會發現為何 class 後面接著沒看過的內容,例如 .page[b-mxoy4q7bj7] 或是 .main[b-mxoy4q7bj7],這是 Blazor 用來辨識 CSS 選擇器作用在哪個 Component 的區域識別碼,格式為 b-10 位元數字及英文字串,每個 Component 的區域識別碼都是獨一無二的,可知這裡的 .main 及 .page class 只作用於 [b-mxoy4q7bj7] 對應的 Component,註解寫著 /* _content/BlazorServer/Shared/MainLayout.razor.rz.scp.css */,打開 Shared/MainLayout.razor.css,的確看到了 .main 及 .page class,rz.scp.css 附檔名是用來辨識 CSS 選擇器屬於哪個 Component。
我們在 Blog.razor.css 加上一段針對 label 的樣式修改,按下 ctrl + shift + B 建置專案,再看網頁就能看到文字顏色改變了,BlazorServer.style.css 也能看到 Blog.razor.rz.scp.css 的樣式區塊多了一段 label[b-0ae5hiw99t]。
label {
color: darkcyan
}

如果想對 Post Component 的 label 元素套用相同樣式,又不想分別建立 razor.css 檔案呢?Blazor 提供了方便的做法,只要在 CSS 選擇器前面加上 ::deep 即可,我們在 Blog.razor.css 的 label 前面加上 ::deep,就能看到 Post 的 label 元素顏色都改變了,BlazorServer.style.css 的 class 也從 label[b-0ae5hiw99t] 變成了 [b-0ae5hiw99t] label。


不過要注意的是,必須有父子關係 ::deep 才能生效,Parent Compoent 的區域識別碼僅作用於 <div> 標籤,如果 Child Component 沒有被 <div> 標籤包住就不會生效。我們把 Blog.razor 中包住 Post Component 的 <div> 標籤都註解,儲存後再去網頁看,發現 <label> 文字顏色都變回黑色了,但 BlazorServer.style.css 的 class 仍舊是 [b-0ae5hiw99t] label。

Ref: ASP.NET Core Blazor CSS isolation