上一篇一路從 SCSS 追到 CSS,再追到瀏覽器。
追到最後,我發現很多共用 CSS、JavaScript,甚至 Header、Sidebar、Footer,根本不在目前這支 Index.cshtml 裡。
這時候就會遇到:
_Layout.cshtml
一開始我看到它,只知道好像跟「版型」有關。
但真的要改企業專案時,比起只知道它是共用版型,更重要的是:
_Layout.cshtml 到底怎麼用?
View 怎麼套上它?
@RenderBody() 到底放了什麼?
我要怎麼從目前頁面找到它?
修改它又會影響哪些地方?
這篇就直接從實際使用方式來看。
_Layout.cshtml 可以先理解成網站的共用外框假設一個系統有很多頁面:
首頁
最新消息
使用者管理
專案管理
設定頁
每一頁中間的內容可能不一樣。
但通常會共用:
Header
Sidebar
Footer
網站 Logo
導覽列
共用 CSS
共用 JavaScript
如果每一個 .cshtml 都重新寫一次這些內容,之後 Header 改一個按鈕,就可能要改很多頁。
所以 MVC 會把這些共用內容集中到 Layout。
最常見的位置是:
Views
└── Shared
└── _Layout.cshtml

_Layout.cshtml?我目前會把它記成四個步驟:
1. 建立 _Layout.cshtml
2. 在 Layout 裡放 @RenderBody()
3. 指定 View 要使用這個 Layout
4. 一般 View 只寫自己這一頁的內容
先從最基本的結構開始。
_Layout.cshtml例如:
Views
└── Shared
└── _Layout.cshtml
內容可以先很簡單:
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="utf-8" />
<title>@ViewData["Title"]</title>
</head>
<body>
<header>
<h1>我的網站</h1>
</header>
<main>
@RenderBody()
</main>
<footer>
<p>共用 Footer</p>
</footer>
</body>
</html>
這支檔案主要負責:
完整 HTML 外框
共用 Header
共用 Footer
共用 CSS
共用 JavaScript
真正每一頁不同的內容,則會放在:
@RenderBody()
這裡。
至於共用 CSS、JavaScript,也很常在 Layout 裡統一載入,只是這篇先不把完整標籤放進範例裡。
可以先理解成:
_Layout.cshtml
會負責:
共用 HTML 結構
共用 CSS
共用 JavaScript
共用 Header
共用 Sidebar
共用 Footer
@RenderBody()假設 Layout 裡有:
<main>
@RenderBody()
</main>
可以先把它理解成:
這裡先空著
等目前 View 執行時
再把那一頁自己的內容塞進來
例如 Index.cshtml:
<h2>首頁</h2>
<p>這是首頁內容。</p>
最後這段內容就會被放進:
@RenderBody()
的位置。
也就是:
_Layout.cshtml
↓
Header
@RenderBody()
↓
Index.cshtml 的內容
Footer

所以 @RenderBody() 我現在會直接把它記成:
目前這個 View 的主要內容
要被放進來的位置
最直接的方式,是在 View 裡寫:
@{
Layout = "_Layout";
}
例如:
@{
Layout = "_Layout";
ViewData["Title"] = "首頁";
}
<h2>首頁</h2>
<p>這是首頁內容。</p>
這代表:
Index.cshtml
↓
使用 _Layout.cshtml
如果目前專案有:
Views/Shared/_Layout.cshtml
就可以使用這個共用版型。
Layout = "_Layout"如果有很多 View:
Index.cshtml
Create.cshtml
Edit.cshtml
Detail.cshtml
History.cshtml
每一頁都寫:
@{
Layout = "_Layout";
}
其實很重複。
所以更常見的是:
Views
└── _ViewStart.cshtml
裡面統一設定:
@{
Layout = "_Layout";
}
這樣底下的 View 通常就不用自己再寫。
專案結構可能長這樣:
Views
├── _ViewStart.cshtml
│
├── Shared
│ └── _Layout.cshtml
│
└── Home
├── Index.cshtml
└── About.cshtml
關係就是:
_ViewStart.cshtml
↓
指定使用 _Layout.cshtml
_Layout.cshtml
↓
提供共用外框
Index.cshtml
↓
提供首頁自己的內容
下一篇會再詳細整理 _ViewStart.cshtml。

假設:
Views/Home/Index.cshtml
只需要寫:
@{
ViewData["Title"] = "首頁";
}
<h1>首頁</h1>
<p>這是首頁自己的內容。</p>
不需要在每一支 View 裡都重新寫完整的:
html
head
body
因為這些共用的外框已經放在 _Layout.cshtml 裡。
所以可以先理解成:
_Layout.cshtml
提供:
html
head
body
Header
Footer
共用 CSS
共用 JavaScript
+
Index.cshtml
提供:
首頁自己的內容
MVC 再把 Index.cshtml 的內容放進:
@RenderBody()
假設 _Layout.cshtml 是:
<body>
<header>
共用 Header
</header>
<main>
@RenderBody()
</main>
<footer>
共用 Footer
</footer>
</body>
Index.cshtml 是:
<h2>首頁</h2>
<p>歡迎來到首頁。</p>
最後產生的 HTML,可以先想成:
body
├─ Header
│ └─ 共用 Header
│
├─ main
│ ├─ 首頁
│ └─ 歡迎來到首頁
│
└─ Footer
└─ 共用 Footer
也就是:
Layout
+
View
↓
完整 HTML
_Layout.cshtml 嗎?不是。
瀏覽器最後收到的仍然只是 HTML。
流程是:
_Layout.cshtml
+
Index.cshtml
↓
Razor 在伺服器端處理
↓
產生完整 HTML
↓
回傳瀏覽器
所以瀏覽器根本不知道:
這段原本來自 _Layout.cshtml
這段原本來自 Index.cshtml
它只看到最後組好的 HTML。
這點跟前面幾篇其實可以接起來。
瀏覽器最後真正認得的還是:
HTML
CSS
JavaScript
.cshtml 是伺服器端拿來產生 HTML 的 Razor View。
不一定。
如果內容很短,可以直接寫在 _Layout.cshtml。
但企業專案裡這些區塊通常比較大,所以也可能拆出去:
Views
└── Shared
├── _Layout.cshtml
├── _Header.cshtml
├── _Sidebar.cshtml
└── _Footer.cshtml
Layout 再把它們組起來。
概念上可以想成:
_Layout.cshtml
├─ _Header.cshtml
│
├─ _Sidebar.cshtml
│
├─ @RenderBody()
│
└─ _Footer.cshtml
所以 Layout 也可以理解成:
負責把整個頁面的大架構組起來
至於這些 _Header.cshtml、_Sidebar.cshtml 怎麼放進 Layout,後面講 Partial View 時再整理。
這就跟上一篇接起來。
假設有一支共用 CSS:
~/css/site.css
還有一支共用 JavaScript:
~/js/site.js
如果是在 _Layout.cshtml 裡統一載入,所有使用這個 Layout 的頁面通常就都會一起使用。
所以像這些:
網站基本樣式
Header 樣式
Sidebar 樣式
Bootstrap
共用 JavaScript
就很適合集中在 Layout。
這也是為什麼我有時候明明在:
Index.cshtml
裡完全找不到:
site.css
但瀏覽器畫面還是有樣式。
因為它可能根本不是在這支 View 裡載入,而是在:
_Layout.cshtml
統一處理。
所以追畫面時,不能只看目前這一支 .cshtml。
不一定。
這是實際工作時很重要的一個判斷。
假設需求是:
首頁的卡片間距要調大
如果只有首頁要改,就不一定要碰:
_Layout.cshtml
因為 Layout 可能是很多頁共用的。
如果直接修改:
共用容器
共用 Header
共用 Sidebar
共用 CSS
其他頁面也可能一起被影響。
所以我現在會先問:
這個修改是全站共用?
還是只有目前這一頁?
如果需求是:
全站 Header 多一個按鈕
比較可能去找:
Layout
或 Header Partial
如果需求是:
只有首頁多一張卡片
通常應該先去找:
Index.cshtml
而不是直接改 Layout。
實際追專案時,我會這樣找。
先打開目前 View:
Views/Home/Index.cshtml
第一步先看上方有沒有:
@{
Layout = "_Layout";
}
如果有,就直接知道目前指定的是哪一個 Layout。
如果沒有,再找:
_ViewStart.cshtml
看裡面是不是有:
@{
Layout = "_Layout";
}
接著再去找:
Views/Shared/_Layout.cshtml
找到實際版型。
最後在 _Layout.cshtml 搜尋:
@RenderBody()
就可以知道:
目前 Index.cshtml 的內容
最後會被放在哪個位置
我的追法會是:
目前 View
↓
有沒有自己指定 Layout?
↓
沒有就找 _ViewStart.cshtml
↓
找到 Layout 名稱
↓
開啟 _Layout.cshtml
↓
找到 @RenderBody()
↓
對照瀏覽器畫面
這也是我現在看到一個 MVC 頁面時,很常用的追法。
_Layout.cshtml 前,我會先確認什麼?因為 Layout 可能一次影響很多頁面,所以我現在不會看到東西就直接改。
我會先確認:
1. 目前 View 使用的是不是這個 Layout?
2. 這個 Layout 有沒有被其他頁面共用?
3. 我要改的是共用區塊,還是單頁內容?
4. CSS 和 JavaScript 是全站需要,還是只有目前頁面需要?
修改後也不能只測目前這一頁。
至少還會看看:
Header 有沒有跑版
Sidebar 有沒有壞
其他頁面是否正常
CSS 是否正常載入
JavaScript 是否正常
因為:
改 Index.cshtml
可能只影響首頁
改 _Layout.cshtml
可能一次影響很多頁
這個差別在企業專案裡很重要。
不是。
一個專案裡完全可能同時有:
_Layout.cshtml
一般系統頁面
_AdminLayout.cshtml
後台頁面
_LoginLayout.cshtml
登入頁面
某個 View 也可以另外指定:
@{
Layout = "_AdminLayout";
}
所以 Layout 不是:
整個專案只能有一個版型
而是:
一群頁面可以共用同一個版型
不同類型的頁面,也可以使用不同 Layout。
@RenderBody() 可以有很多個嗎?一般 Layout 會有一個主要的:
@RenderBody()
它負責放:
目前 View 的主要內容
但有時候除了主要內容之外,某些頁面還需要自己的:
頁面專用 JavaScript
頁面專用 CSS
額外區塊
這時候就可能會看到:
RenderSection
RenderBody 和 RenderSection 的用途不太一樣,後面會再一起整理。
_Layout.cshtml 的起手式如果今天自己建立一個最小 MVC View 結構,我會先這樣做。
Views/_ViewStart.cshtml@{
Layout = "_Layout";
}
Views/Shared/_Layout.cshtml<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>@ViewData["Title"]</title>
</head>
<body>
<header>
<h1>我的網站</h1>
</header>
<main>
@RenderBody()
</main>
<footer>
<p>共用 Footer</p>
</footer>
</body>
</html>
Views/Home/Index.cshtml@{
ViewData["Title"] = "首頁";
}
<h2>首頁</h2>
<p>這是首頁自己的內容。</p>
三支檔案的工作就是:
_ViewStart.cshtml
↓
決定使用哪個 Layout
_Layout.cshtml
↓
提供共用版型
並用 @RenderBody() 預留主要內容位置
Index.cshtml
↓
提供目前頁面自己的內容
這就是 _Layout.cshtml 最基本也最實際的使用方式。
_Layout.cshtml 不是單純「另一支 .cshtml」。
它的主要用途是:
建立多個 View 共用的頁面外框
最常見的實際用法可以整理成:
Views/_ViewStart.cshtml
↓
指定:
Layout = "_Layout"
↓
Views/Shared/_Layout.cshtml
↓
建立共用:
Header
Sidebar
Footer
CSS
JavaScript
並放:
@RenderBody()
↓
Views/Home/Index.cshtml
↓
只寫首頁自己的內容
最後:
_Layout.cshtml
+
Index.cshtml
↓
Razor
↓
完整 HTML
↓
瀏覽器
所以之後接到畫面修改需求時,我現在會先判斷:
這是單頁內容?
→ 找目前 View
這是共用 Header、Sidebar、Footer?
→ 找 Layout 或 Partial View
不知道目前用了哪個 Layout?
→ 從 View 和 _ViewStart.cshtml 往回找
這樣 _Layout.cshtml 就不是只停在「共用版型」四個字,而是真的知道在專案裡要去哪裡找、怎麼使用,以及修改前要注意什麼。
下一篇接著整理:
_ViewStart.cshtml和_ViewImports.cshtml都放在 Views 裡,也都有底線,它們到底各自在幫 View 做什麼?