問題情境
專案部署到 IIS 的虛擬目錄,URL 結構如下:
- 本機:
http://localhost:56961/Project/ - 正式環境:
https://www.project.com.tw/Project/
HTML 裡的圖片路徑寫 ./Content/images/image.png,本機跑得好好的,上正式就全破圖。
實際原因:./ 是相對路徑,參考點是「解析該路徑的檔案位置」,不是 HTML 頁面。若圖片路徑寫在外部 .css 檔(例如放在 /Project/styles/main.css),瀏覽器會以 CSS 檔的目錄為基準,把 ./Content/images/image.png 解析成 /Project/styles/Content/images/image.png,而非你預期的 /Project/Content/images/image.png。
換部署位置(從本機 localhost 換到子目錄或反向代理後方)時,CSS 檔的實際 URL 路徑可能跟著變,就會踩到這個問題。
三種解法
方案一:硬寫絕對路徑
1 | background: url("/Project/Content/images/image.png"); |
開頭的 / 讓瀏覽器從網域根目錄算起,不受 CSS 檔或 HTML 檔的位置影響。
真正的缺點:路徑硬寫了 /Project/ 這個子目錄前綴。換部署位置(例如從 /Project/ 移到根目錄)時,要全站搜尋替換所有絕對路徑。適合子目錄名稱永遠不變的長期專案。
方案二:ASP.NET MVC URL Helper
@Url.Content() 只能在 Razor 的 .cshtml 裡執行,不能放在外部 .css 靜態檔。正確用法是在 Razor layout 或 view 的 <style> 區塊,或直接用在 <img> 的 src 屬性:
1 | <!-- 在 .cshtml 的 <img> 標籤 --> |
~/ 代表應用程式根目錄,ASP.NET 會自動補上 /Project/ 前綴,換部署路徑時不需要改程式碼。
缺點:只限 Razor 視圖能用;外部 .css 靜態檔完全無效。
方案三:設定 HTML <base> tag(推薦)
1 | <head> |
設了 <base> 後,頁面上所有相對路徑(包括從外部 CSS 的 url() 繼承效果之外、HTML 裡的 src、href)都以 base href 為起點計算。只要在 layout 改一個地方,換部署路徑時也只改這一行。
使用前必須知道的限制:
頁內錨點會壞掉:
<a href="#section">會被解析成https://www.project.com.tw/Project/#section,瀏覽器會先離開當前頁面再跳回來,而非在頁內捲動。有目錄或錨點跳轉的頁面,必須把所有錨點改成完整絕對 URL(<a href="/Project/page.html#section">)。SPA 路由需要額外處理:用
history.pushState或 hash 路由的 SPA 框架(Vue Router、React Router)必須設定對應的base選項,否則路由計算會偏移。必須放在
<head>最前面:<base>要在任何使用相對路徑的<link>、<script>、<img>之前出現,否則已解析過的相對路徑不會重新計算。
最佳實踐
按場景選工具,別只看優點:
- 純靜態 HTML 站,部署到子目錄:用
<base>tag,是最省事的方案,但先確認頁面沒有頁內錨點。 - ASP.NET MVC 且圖片路徑在 Razor 模板裡:用
@Url.Content("~/..."),讓框架幫你算路徑。 - 現代前端工具鏈(Vite、Webpack):設定
base(Vite)或publicPath(Webpack);打包時工具會自動替換所有資源路徑,不需要手動維護任何方案一或方案三。 - 絕對路徑方案適合最簡單的情況:部署路徑固定且不使用框架。
最根本的預防方式:在專案初期就確定部署路徑的結構,避免本機跑根目錄、正式環境跑子目錄這類不一致的情境。




