早期 Web 開發時有一種說法請求太多會影響頁面性能如果您知道有什麼技巧可以減少網頁所觸發的 HTTP 請求數盡可能使用這些方法吧隨著網頁中越來越多地填充了豐富的視覺內容下載 CSS腳本和圖像等相關資源所需的成本顯著攀升毫無疑問在大多數情況下這些資源可由浏覽器緩存到本地但保持最初占用的空間會是非常困難的此外減少請求的數量和大小也有助於確保低帶寬占用降低延遲以及延長電池壽命在移動浏覽中這些都是關鍵因素解決這些問題最普遍接受的方法包含了兩個操作的結合捆綁和縮小
在本文中我將從 ASPNET MVC 提供的軟件工具的獨有角度出發介紹 CSS 文件的捆綁和縮小這一話題延續了我之前的專欄在 ASPNET MVC 中創建為移動設備優化的視圖第 部分使用 WURFL(msd/magazine/dn)
捆綁和縮小的基礎知識
捆綁是將多個不同資源匯總成為單個可下載資源的過程例如一個捆綁中可能包括多個 JavaScript 或 CSS 文件您可以通過向某個特定端點發送單個 HTTP 請求將這些內容下載到本地計算機另一方面縮小是對資源應用的轉換具體而言縮小是從基於文本的資源中刪除所有不必要字符的過程這一過程不會改變預期功能這意味著縮短標識符對函數使用別名以及刪除注釋空格字符和新行一般來說添加這些所刪除字符通常是為了提升可讀性但是會占用空間並且實際不起到任何功能用途
捆綁和縮小可同時應用但過程彼此獨立根據需要您可以決定只創建捆綁或者只縮小單獨文件不過通常在生產站點上沒有理由不捆綁和縮小所有 CSS 及 JavaScript 文件當然也有一些例外諸如 jQuery 等公共資源可能會位於眾所周知的內容交付網絡 (CDN) 上但是在調試時這就是完全不同的情況經過縮小或者捆綁的資源非常難於閱讀和單步執行因此您可能不希望啟用捆綁和調試
許多框架提供了捆綁和縮小服務其可擴展性水平略有差別並且采用了不同的功能集大多數情況下它們提供了相同的功能因此選擇哪一種純屬個人偏好如果您正在編寫 ASPNET MVC 應用程序則捆綁和縮小的選擇自然就是 Microsoft ASPNET Web Optimization Framework該框架在 NuGet 程序包 (bitly/bSuB) 中提供如圖 中所示
圖 安裝 Microsoft ASPNET Web Optimization Framework
使用 CSS 捆綁
就我認為了解 CSS 捆綁機制的最佳方法是從一個真正的空 ASPNET MVC 項目開始著手這意味著使用空項目模板來創建新項目並刪除未使用的引用和文件接下來假定您添加鏈接多個 CSS 文件的布局文件
<link rel="stylesheet"
href="@UrlContent("~/content/styles/sitecss")"/>
如果使用 Fiddler 或 Internet Explorer 開發者工具顯示頁面並監視其網絡活動您會發現有兩個並行下載 這是默認行為
請注意在 ASPNET MVC 中您可以使用新的 StylesRender 工具以緊湊得多的方式重寫以前的標記
@StylesRender(
"~/content/styles/sitecss"
"~/content/styles/sitemorecss")
位於 SystemWebOptimization 下的 Styles 類的功能遠比第一眼看到的要強大 StylesRender 方法也支持捆綁 這意味著該方法有多個重載其中一個接受 CSS URL 數組 不過另一個重載接受以前創建的捆綁的名稱(稍後將進一步介紹) 在本例中它發出單個 <link> 元素並使其指向自動生成的 URL該 URL 返回經過捆綁或縮小的所有樣式表
創建 CSS 捆綁
通常在 globalasax 中以編程方式創建捆綁 按照配置代碼的 ASPNET MVC 模式您可能需要在 App_Start 文件夾下創建 BundleConfig 類並在其外部公開靜態初始化方法
BundleConfigRegisterBundles(BundleTableBundles);
一個 CSS 捆綁只是一個樣式表集合 此處是將上述兩個 CSS 文件分組到單個下載中的代碼
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
// Register bundles first
bundlesAdd(new Bundle("~/mycss")Include(
"~/content/styles/sitecss"
"~/content/styles/sitemorecss"));
BundleTableEnableOptimizations = true;
}
}
創建新 Bundle 類將用於從視圖或網頁中引用捆綁的虛擬路徑傳遞到構造函數中 也可以在以後通過 Path 屬性來設置虛擬路徑 要將 CSS 文件與捆綁關聯需要使用 Include 方法 此方法接受表示虛擬路徑的字符串數組 您可以按上例中所示明確指示 CSS 文件也可以按此處所示指示模式字符串
bundlesAdd(new Bundle("~/mycss")
Include("~/content/styles/*css");
Bundle 類還有 IncludeDirectory 方法該方法可用於指示給定虛擬目錄的路徑還可使用模式匹配字符串和布爾標志來啟用對子目錄的搜索
在之前代碼片段中看到的在 BundleTable 類上設置的 EnableOptimization 布爾屬性表示需要顯式啟用捆綁 如果未以編程方式啟用則捆綁無法正常工作 如前所述捆綁是一種優化方式因此當站點是生產站點時通常很有意義 EnableOptimization 屬性是一種設置捆綁的簡便方法應在生產中使用不過以調試模式編譯站點時應該禁用它 您甚至可以使用以下代碼
if (!DEBUG)
{
BundleTableEnableOptimizations = true;
}
更多高級捆綁功能
就 CSS 捆綁而言除了縮小之外沒有多少其他相關內容 不過BundleCollection 類是一個通用類也可用於捆綁腳本文件 特別是BundleCollection 類有幾個功能值得注意雖然它們在捆綁腳本文件而非 CSS 文件時最有用
第一個功能是排序 BundleCollection 類有一個名為 Orderer 的屬性其類型為 IBundleOrderer 正如您所見orderer 是一個負責確定您希望在捆綁文件以供下載時使用的實際順序的組件 默認 orderer 是 DefaultBundleOrderer 類 此類按照 BundleCollection 屬性 FileSetOrderLis 的設置所得到的順序來捆綁文件 FileSetOrderList 設計作為 BundleFileSetOrdering 類的集合 這些類中的每一個都定義文件的模式(例如 jquery*)BundleFileSetOrdering 類添加到 FileSetOrderList 的順序確定了文件的實際順序 例如在使用默認配置時所有 jQuery 文件始終捆綁在 Modernizr 文件之前
DefaultBundleOrderer 類對 CSS 文件的影響則有限得多 如果您的網站中有名為resetcss或normalizecss的文件則這些文件將自動捆綁在您的任意 CSS 文件之前並且 resetcss 始終要優先於 normalizecss 如果您不熟悉重置/規范化樣式表那麼這些樣式表可以為所有 HTML 元素提供標准樣式屬性集這樣您的頁面不會繼承特定於浏覽器的設置例如字體字號和邊距 雖然這兩種類型的 CSS 文件都有一些推薦的內容但實際內容取決於您 如果您的項目中有這些名稱的文件則 ASPNET MVC 會通過額外方式確保這些文件捆綁在所有其他內容之前 如果您希望覆蓋默認 orderer 並忽略預定義的捆綁文件集排序可以使用兩個選項 首先可以針對每次捆綁創建自定義 orderer 下面是一個簡單地忽略預定義排序的示例
public class PoorManOrderer : IBundleOrderer
{
public IEnumerable<FileInfo> OrderFiles(
BundleContext context IEnumerable<FileInfo> files)
{
return files;
}
}
您可以按下面所示的方式使用
var bundle = new Bundle("~/mycss");
bundleOrderer = new PoorManOrderer();
此外可以使用下列代碼重置所有排序
bundlesResetAll();
在本例中使用默認 orderer 的效果與之前窮人 orderer 的效果相同 不過請注意ResetAll 還將重置腳本排序
另一個更高級的功能是忽略列表 它通過 BundleCollection 類的 IgnoreList 屬性針對已選中包含的文件(但實際上應該忽略)定義模式匹配字符串 在 ASPNET MVC 中實現捆綁的主要優勢是可以在單次調用中獲取文件夾中的所有 JavaScript 文件 (*js) 但是有可能 *js 還會匹配您不希望下載的文件例如 vsdocjs 文件 IgnoreList 的默認配置考慮到了大多數常見情況同時也允許自定義
運行中的 CSS 捆綁
CSS 捆綁是一種強大的優化功能但是在實際過程中是如何工作的? 請考慮使用以下代碼
var bundle = new Bundle("~/mycss");
bundleInclude("~/content/styles/*css");
bundlesAdd(bundle);
圖 中顯示了對應的 HTTP 通信
圖 第二個請求是有多個 CSS 文件的捆綁
第一個請求針對是主頁第二個請求不指向特定 CSS 文件而是引用了包含 content/styles 文件夾中所有 CSS 文件的捆綁(請參閱圖 )
圖 捆綁 CSS 示例
添加縮小功能
只有在將多個資源打包到一起以便通過單個下載捕獲並進行緩存時才需要使用 Bundle 類
正如圖 中的代碼所示下載的內容中添加了空白和新行字符以便於閱讀不過浏覽器並不關心可讀性對於浏覽器來說圖 中的 CSS 代碼完全等同於以下縮小代碼中的字符串
htmlbody{fontfamily:;segoe ui;;fontsize:em;margin:px}
htmlbody{backgroundcolor:#;color:#dcc}
對於我在此例中使用的簡單 CSS縮小功能可能並沒有起到多大作用 但是對於具有大量樣式表的商務站點縮小 CSS 就非常有意義
如何添加縮小功能? 非常簡單就像使用 StyleBundle 替換 Bundle 類一樣 StyleBundle 出奇的簡單它繼承自 Bundle僅由不同的構造函數組成
public StyleBundle(string virtualPath)
: base(virtualPath new IBundleTransform[] { new CssMinify() })
{
}
Bundle 類具有可接受 IBundleTransform 對象列表的構造函數 這些轉換將逐個應用於內容 StyleBundle 類僅添加 CssMinify 轉換器 CssMinify 是 ASPNET MVC (和更高版本)的默認縮小器基於 WebGrease 優化工具 (webgreas) 無需贅言如果您希望切換到不同縮小器則需要做的就是獲取類(IBundleTransform 的實現)並通過類 Bundle 的構造函數進行傳遞
再也不用找托辭
隨 ASPNET MVC 捆綁的 Web Optimization Framework 添加了少量功能不過這些都是非常有用的功能 這就沒有任何理由不去縮小和捆綁資源 到目前為止可能的托辭都是 ASPNET 平台中缺少原生支持 ASPNET MVC 和更高的版本中不再是這種情況
不過對於 CSS 文件而言還有另一個方面需要考慮動態生成樣式 CSS 最初只是設計作為應用到網頁的外觀效果現在正在轉變成為更加動態的資源已經引入了一些偽編程語言來以編程方式生成 CSS 這些主題將在下次介紹
From:http://tw.wingwit.com/Article/program/Web/201405/30992.html