demoshop

demo, trying to be the best_

最近因為一些原因,加快了我把某專案升級為 .NET 6 的時程,升級之前當然是要做些 POC 最簡單的就是建立一個範本專案,然後跑一些重點需求,確保這些需求的執行結果如預期,而在開啟範本專案後,有一個東西吸引了我的眼球,如是我就開始研究進去了…            

誰吸引了我的注意

就是這個 _Layout.cshtml.css 吸引了我 

專案範本分析

範本專案建立有兩個 css 一個是放在靜態檔案內的 site.css 另一個就是這個 _Layout.cshtml.css 首先來看一下它們的內容

/*這是 site.css*/
html {
  font-size: 14px;
}

@media (min-width: 768px) {
  html {
    font-size: 16px;
  }
}

html {
  position: relative;
  min-height: 100%;
}

body {
  margin-bottom: 60px;
}      
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */

a.navbar-brand {
  white-space: normal;
  text-align: center;
  word-break: break-all;
}

a {
  color: #0077cc;
}

.btn-primary {
  color: #fff;
  background-color: #1b6ec2;
  border-color: #1861ac;
}

.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
  color: #fff;
  background-color: #1b6ec2;
  border-color: #1861ac;
}

.border-top {
  border-top: 1px solid #e5e5e5;
}
.border-bottom {
  border-bottom: 1px solid #e5e5e5;
}

.box-shadow {
  box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}

button.accept-policy {
  font-size: 1rem;
  line-height: inherit;
}

.footer {
  position: absolute;
  bottom: 0;
  width: 100%;
  white-space: nowrap;
  line-height: 60px;
}

看結構就可以發現,site.css 負責了大範圍較頂層的樣式,_layout.cshtml.css 則負責了預設 Layout 的樣式,然後再來看看到底 Layout 載入了哪些 CSS

    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/WebApplication7.styles.css" asp-append-version="true" />
    <!-- 我的專案名稱是 WebApplication7 -->

不存在的 css

嗯...有各怪東西,這世界上沒有 WebApplication7.styles.css 這個檔案才對,但卻可以正常載入

再來看看 WebApplication7.styles.css 這個檔案有什麼內容


/* _content/WebApplication7/Pages/Shared/_Layout.cshtml.rz.scp.css */
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */

a.navbar-brand[b-0lpt38urcm] {
  white-space: normal;
  text-align: center;
  word-break: break-all;
}

a[b-0lpt38urcm] {
  color: #0077cc;
}

.btn-primary[b-0lpt38urcm] {
  color: #fff;
  background-color: #1b6ec2;
  border-color: #1861ac;
}

.nav-pills .nav-link.active[b-0lpt38urcm], .nav-pills .show > .nav-link[b-0lpt38urcm] {
  color: #fff;
  background-color: #1b6ec2;
  border-color: #1861ac;
}

.border-top[b-0lpt38urcm] {
  border-top: 1px solid #e5e5e5;
}
.border-bottom[b-0lpt38urcm] {
  border-bottom: 1px solid #e5e5e5;
}

.box-shadow[b-0lpt38urcm] {
  box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}

button.accept-policy[b-0lpt38urcm] {
  font-size: 1rem;
  line-height: inherit;
}

.footer[b-0lpt38urcm] {
  position: absolute;
  bottom: 0;
  width: 100%;
  white-space: nowrap;
  line-height: 60px;
}

打開看以後發現目前的 WebApplication7.styles.css 內容與 _Layout.cshtml.css 的內容一模一樣😅 

目前已知的情報

  1. 在網站執行後會動態產生一個專案名稱的樣式檔。
  2. 樣式檔內會包含 _Layout.cshtml.css 的內容。

css isolation

CSS 隔離,其實這是滿多前端框架有的功能,原先是搬到 Blazor 後來才在 Razor Pages 實做,我們來看看他的效果。

Index.cshtml.css

在專案增加一個 Index.cshtml.css,並且內容給一個很簡單的樣式

h1 {
    font-size: 120px;
    color:seagreen
}

依據上述的樣式因該所有的 h1 標籤內容都會變綠色變大,立即將網頁執行看看。(記得編譯,CSS isolation 不支援 Hot Reload)

實際測試

左邊 Index 的 H1 效果有出來,右邊 Privacy 的 H1 並沒有受到影響

怎麼隔離的?

在原始檔中可以觀察到有部分的標籤被加上了奇怪的編號(HTML 屬性)  

目前的編號有兩組 

再一次使用瀏覽器的開發者工具,開啟WebApplication7.styles.css觀察內容

/* _content/WebApplication7/Pages/Index.cshtml.rz.scp.css */
h1[b-4cjiczgryv] {
    font-size: 120px;
    color:seagreen
}
/* _content/WebApplication7/Pages/Shared/_Layout.cshtml.rz.scp.css */
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */

a.navbar-brand[b-0lpt38urcm] {
  white-space: normal;
  text-align: center;
  word-break: break-all;
}

a[b-0lpt38urcm] {
  color: #0077cc;
}

.btn-primary[b-0lpt38urcm] {
  color: #fff;
  background-color: #1b6ec2;
  border-color: #1861ac;
}

.nav-pills .nav-link.active[b-0lpt38urcm], .nav-pills .show > .nav-link[b-0lpt38urcm] {
  color: #fff;
  background-color: #1b6ec2;
  border-color: #1861ac;
}

.border-top[b-0lpt38urcm] {
  border-top: 1px solid #e5e5e5;
}
.border-bottom[b-0lpt38urcm] {
  border-bottom: 1px solid #e5e5e5;
}

.box-shadow[b-0lpt38urcm] {
  box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}

button.accept-policy[b-0lpt38urcm] {
  font-size: 1rem;
  line-height: inherit;
}

.footer[b-0lpt38urcm] {
  position: absolute;
  bottom: 0;
  width: 100%;
  white-space: nowrap;
  line-height: 60px;
}

可以看見屬性的對應是看該樣式寫在  WebApplication7.styles.cssIndex.cshtml.css中,利用這樣的技巧,可以確實達到 CSS 隔離的需求。 

優點

開發者在利用 CSS isolation 技術可以降低對於 CSS 優先權觀念的理解,寫在哪個頁面就只有哪個頁面會生效,不再需要自己想一堆不同的 css class name 來隔離,且對於一些豐富樣式的套件更是合適。

雖然看起來效果與在頁面內開<style>區塊寫一樣,但寫在頁面內的樣式是無法快取的,此技巧可以將所有的檔案包裝為一個檔,有利瀏覽器快取命中。   

推薦的應用情境

上述的優點剛好也就是它的缺點,假設團隊是有專業的前端人員,依據他們的習慣來處理 CSS 檔案對雙方都好。但專案後期或維護期因成本考量通常前端人員會去支援另一個早期專案,丟給不懂 CSS 的後端人員來搞,很容易影響到一些未預期的標籤,這時候利用 CSS isolation 技術來有效隔離就是各不錯的選擇!

使用方式

檔案名稱就是依據,將原本的$"{檔案名稱}{副檔名}.css"就可觸發,以下為範例

  • _Layout.cshtml
    • _Layout.cshtml.css
  • Index.cshtml
    • Index.cshtml.css
  • About.cshtml
    • About.cshtml.css

載入的時候是使用${專案名稱}.style.css

目前只有 Bundle 沒有 Minify

系列文章

  • .NET6 的 CSS 隔離 css isolation

回應討論