早期 Web 开发时有一种说法 请求太多会影响页面性能 如果您知道有什么技巧可以减少网页所触发的 HTTP 请求数 尽可能使用这些方法吧 随着网页中越来越多地填充了丰富的视觉内容 下载 CSS 脚本和图像等相关资源所需的成本显著攀升 毫无疑问 在大多数情况下 这些资源可由浏览器缓存到本地 但保持最初占用的空间会是非常困难的 此外 减少请求的数量和大小也有助于确保低带宽占用 降低延迟以及延长电池寿命 在移动浏览中 这些都是关键因素 解决这些问题最普遍接受的方法包含了两个操作的结合 捆绑和缩小
在本文中 我将从 ASP NET MVC 提供的软件工具的独有角度出发 介绍 CSS 文件的捆绑和缩小 这一话题延续了我之前的专栏 在 ASP NET MVC 中创建为移动设备优化的视图 第 部分 使用 WURFL (msd/magazine/dn )
捆绑和缩小的基础知识捆绑是将多个不同资源汇总成为单个可下载资源的过程 例如 一个捆绑中可能包括多个 JavaScript 或 CSS 文件 您可以通过向某个特定端点发送单个 HTTP 请求 将这些内容下载到本地计算机 另一方面 缩小是对资源应用的转换 具体而言 缩小是从基于文本的资源中删除所有不必要字符的过程 这一过程不会改变预期功能 这意味着缩短标识符 对函数使用别名以及删除注释 空格字符和新行 一般来说 添加这些所删除字符通常是为了提升可读性 但是会占用空间并且实际不起到任何功能用途
捆绑和缩小可同时应用 但过程彼此独立 根据需要 您可以决定只创建捆绑或者只缩小单独文件 不过 通常在生产站点上 没有理由不捆绑和缩小所有 CSS 及 JavaScript 文件 当然也有一些例外 诸如 jQuery 等公共资源可能会位于众所周知的内容交付网络 (CDN) 上 但是 在调试时这就是完全不同的情况 经过缩小或者捆绑的资源非常难于阅读和单步执行 因此您可能不希望启用捆绑和调试
许多框架提供了捆绑和缩小服务 其可扩展性水平略有差别 并且采用了不同的功能集 大多数情况下 它们提供了相同的功能 因此选择哪一种纯属个人偏好 如果您正在编写 ASP NET MVC 应用程序 则捆绑和缩小的选择自然就是 Microsoft ASP NET Web Optimization Framework 该框架在 NuGet 程序包 (bit ly/ bS u B) 中提供 如 图 中所示
图 安装 Microsoft ASP NET Web Optimization Framework
使用 CSS 捆绑就我认为 了解 CSS 捆绑机制的最佳方法是从一个真正的空 ASP NET MVC 项目开始着手 这意味着使用空项目模板来创建新项目并删除未使用的引用和文件 接下来 假定您添加链接多个 CSS 文件的布局文件
<link rel="stylesheet" href="@Url Content("~/content/styles/site css")"/>
如果使用 Fiddler 或 Internet Explorer 开发者工具显示页面并监视其网络活动 您会发现有两个并行下载 这是默认行为
请注意 在 ASP NET MVC 中 您可以使用新的 Styles Render 工具 以紧凑得多的方式重写以前的标记
@Styles Render( "~/content/styles/site css" "~/content/styles/site more css")
位于 System Web Optimization 下的 Styles 类的功能远比第一眼看到的要强大 Styles Render 方法也支持捆绑 这意味着该方法有多个重载 其中一个接受 CSS URL 数组 不过 另一个重载接受以前创建的捆绑的名称(稍后将进一步介绍) 在本例中 它发出单个 <link>元素并使其指向自动生成的 URL 该 URL 返回经过捆绑或缩小的所有样式表 创建 CSS 捆绑
通常在 global asax 中以编程方式创建捆绑 按照配置代码的 ASP NET MVC 模式 您可能需要在 App_Start 文件夹下创建 BundleConfig 类 并在其外部公开静态初始化方法
BundleConfig RegisterBundles(BundleTable Bundles)
一个 CSS 捆绑只是一个样式表集合 此处是将上述两个 CSS 文件分组到单个下载中的代码
public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { // Register bundles first bundles Add(new Bundle("~/mycss") Include( "~/content/styles/site css" "~/content/styles/site more css")) BundleTable EnableOptimizations = true } }
创建新 Bundle 类 将用于从视图或网页中引用捆绑的虚拟路径传递到构造函数中 也可以在以后通过 Path 属性来设置虚拟路径 要将 CSS 文件与捆绑关联 需要使用 Include 方法 此方法接受表示虚拟路径的字符串数组 您可以按上例中所示明确指示 CSS 文件 也可以按此处所示指示模式字符串
bundles Add(new Bundle("~/mycss") Include("~/content/styles/* css")
Bundle 类还有 IncludeDirectory 方法 该方法可用于指示给定虚拟目录的路径 还可使用模式匹配字符串和布尔标志来启用对子目录的搜索
在之前代码片段中看到的在 BundleTable 类上设置的 EnableOptimization 布尔属性 表示需要显式启用捆绑 如果未以编程方式启用 则捆绑无法正常工作 如前所述 捆绑是一种优化方式 因此当站点是生产站点时通常很有意义 EnableOptimization 属性是一种设置捆绑的简便方法 应在生产中使用 不过以调试模式编译站点时应该禁用它 您甚至可以使用以下代码
if (!DEBUG) { BundleTable EnableOptimizations = true }
更多高级捆绑功能
就 CSS 捆绑而言 除了缩小之外 没有多少其他相关内容 不过 BundleCollection 类是一个通用类 也可用于捆绑脚本文件 特别是 BundleCollection 类有几个功能值得注意 虽然它们在捆绑脚本文件而非 CSS 文件时最有用
第一个功能是排序 BundleCollection 类有一个名为 Orderer 的属性 其类型为 IBundleOrderer 正如您所见 orderer 是一个负责确定您希望在捆绑文件以供下载时使用的实际顺序的组件 默认 orderer 是 DefaultBundleOrderer 类 此类按照 BundleCollection 属性 FileSetOrderLis 的设置所得到的顺序来捆绑文件 FileSetOrderList 设计作为 BundleFileSetOrdering 类的集合 这些类中的每一个都定义文件的模式(例如 jquery *) BundleFileSetOrdering 类添加到 FileSetOrderList 的顺序确定了文件的实际顺序 例如 在使用默认配置时 所有 jQuery 文件始终捆绑在 Modernizr 文件之前
DefaultBundleOrderer 类对 CSS 文件的影响则有限得多 如果您的网站中有名为 reset css 或 normalize css 的文件 则这些文件将自动捆绑在您的任意 CSS 文件之前 并且 reset css 始终要优先于 normalize css 如果您不熟悉重置/规范化样式表 那么这些样式表可以为所有 HTML 元素提供标准样式属性集 这样您的页面不会继承特定于浏览器的设置 例如字体 字号和边距 虽然这两种类型的 CSS 文件都有一些推荐的内容 但实际内容取决于您 如果您的项目中有这些名称的文件 则 ASP NET MVC 会通过额外方式确保这些文件捆绑在所有其他内容之前 如果您希望覆盖默认 orderer 并忽略预定义的捆绑文件集排序 可以使用两个选项 首先 可以针对每次捆绑创建自定义 orderer 下面是一个简单地忽略预定义排序的示例
public class PoorManOrderer : IBundleOrderer { public IEnumerable<FileInfo>OrderFiles( BundleContext context IEnumerable<FileInfo>files) { return files } }
您可以按下面所示的方式使用
var bundle = new Bundle("~/mycss") bundle Orderer = new PoorManOrderer()
此外 可以使用下列代码重置所有排序
bundles ResetAll()
在本例中 使用默认 orderer 的效果与之前穷人 orderer 的效果相同 不过请注意 ResetAll 还将重置脚本排序
另一个更高级的功能是忽略列表 它通过 BundleCollection 类的 IgnoreList 属性 针对已选中包含的文件(但实际上应该忽略)定义模式匹配字符串 在 ASP NET MVC 中实现捆绑的主要优势是可以在单次调用中获取文件夹中的所有 JavaScript 文件 (* js) 但是 有可能 * js 还会匹配您不希望下载的文件 例如 vsdoc js 文件 IgnoreList 的默认配置考虑到了大多数常见情况 同时也允许自定义 运行中的 CSS 捆绑
CSS 捆绑是一种强大的优化功能 但是 在实际过程中是如何工作的? 请考虑使用以下代码
var bundle = new Bundle("~/mycss") bundle Include("~/content/styles/* css") bundles Add(bundle)
图 中显示了对应的 HTTP 通信
图 第二个请求是有多个 CSS 文件的捆绑
第一个请求针对是主页 第二个请求不指向特定 CSS 文件 而是引用了包含 content/styles 文件夹中所有 CSS 文件的捆绑(请参阅 图 )
图 捆绑 CSS 示例
添加缩小功能只有在将多个资源打包到一起以便通过单个下载捕获并进行缓存时 才需要使用 Bundle 类
正如 图 中的代码所示 下载的内容中添加了空白和新行字符以便于阅读 不过 浏览器并不关心可读性 对于浏览器来说 图 中的 CSS 代码完全等同于以下缩小代码中的字符串
body{font family:&# segoe ui&# font size: emmargin: px} body{background color:# color:# d cc}
对于我在此例中使用的简单 CSS 缩小功能可能并没有起到多大作用 但是 对于具有大量样式表的商务站点 缩小 CSS 就非常有意义
如何添加缩小功能? 非常简单 就像使用 StyleBundle 替换 Bundle 类一样 StyleBundle 出奇的简单 它继承自 Bundle 仅由不同的构造函数组成
public StyleBundle(string virtualPath) : base(virtualPath new IBundleTransform[] { new CssMinify() }) { }
Bundle 类具有可接受 IBundleTransform 对象列表的构造函数 这些转换将逐个应用于内容 StyleBundle 类仅添加 CssMinify 转换器 CssMinify 是 ASP NET MVC (和更高版本)的默认缩小器 基于 WebGrease 优化工具 (webgreas) 无需赘言 如果您希望切换到不同缩小器 则需要做的就是获取类(IBundleTransform 的实现)并通过类 Bundle 的构造函数进行传递 再也不用找托辞
随 ASP NET MVC 捆绑的 Web Optimization Framework 添加了少量功能 不过 这些都是非常有用的功能 这就没有任何理由不去缩小和捆绑资源 到目前为止 可能的托辞都是 ASP NET 平台中缺少原生支持 ASP NET MVC 和更高的版本中不再是这种情况
lishixinzhi/Article/program/Web/201405/30992
在本文中 我将介绍使用 LESS Framework 动态生成 CSS 内容的 Web 开发
毫无疑问 CSS 代表一大飞跃 它有望将内容与网页显示完全分离 而且在很大程度上实现了这一点 尽管 CSS 属于(或应该属于?)设计人员关注的范畴 它率先提出了关注点分离原则 几乎每个开发人员都对此非常敏感 因此 CSS 很快获得采用 它在 Web 开发过程中如此根深蒂固 以致于有时难于满足最新网站的需求
问题并不是 CSS 不足以满足样式最新 图形丰富并且外观吸引人的网站需求 而是纯粹的声明语言并非始终适合表现复杂的互联样式声明 好在只要编写正确 CSS 对于浏览器仍然合理 但对人来说也是如此吗?
Web 开发中一个相对较新的方向是围绕 CSS 构建基础结构 使开发人员和设计人员能够以可持续性更高的方式生成相同的 CSS 最终的浏览器样式表并无变化 但其生成方式应有所不同 更易读也更容易管理
这一 Web 开发领域出现于几年前 现在日渐成熟 有几个可用的框架可以帮助您进行动态 CSS 内容生成 我将提供其中一个框架 也就是 LESS Framework 的执行概要 并演示它如何与 ASP NET MVC 解决方案集成
为何采用 LESS?
开发人员借助 LESS 解决的最大问题之一 是信息的重复 作为软件开发人员 您可能了解 切勿重复 (DRY) 原则并且每天都在应用 DRY 的主要优点在于 它减少了相同信息的存储位置 因而减少了应更新该信息的位置的数量
对于普通 CSS 您根本不会遇到 DRY 问题 例如 在某些其他情况下 如果多个类中使用某种颜色 而您需要对其进行更改 可能除了逐一更新之外没有更好的办法了 使用 CSS 类可以定义特定元素的外观 并针对样式相关的元素以相同的方式跨页面重复使用 尽管 CSS 类确实可以减少重复 但有时在其他方面显得不足
CSS 类的一个问题是它们在语义 HTML 元素的级别运行 在构建各种 CSS 类时 经常需要重复颜色或宽度等细节信息 对这些可重复细节中的每一个使用同一个类并不方便 即使设法用一个 CSS 类表示几乎所有可重复样式 如颜色和宽度 当开始对语义元素(如容器)应用样式时 还是应该连用多个 CSS 类以便实现所需的效果
如果您曾用 Bootstrap 等框架设计过网页 就会明白我的意思 例如
<a class= btn btn primary />
首先将锚点设置为一个按钮(类 btn) 然后设置为特定风格的按钮(类 btn primary) 这种方法有效 但可能需要进行大量工作提前计划所需的类 这会增加 Web 项目的工作量 而项目往往时间紧迫
LESS 这样的动态样式表语言表示一种横向思维 您不必花时间尝试使普通 CSS 变得更加智能 只需使用不同的工具(一般是语言)进行生成即可 因此 LESS 是一种框架 它向 CSS 编码添加了编程人员友好的概念 如变量 块和函数
与动态 CSS 生成严格相关的 是将其处理为普通 CSS 供浏览器使用的问题 客户端可以通过临时 JavaScript 代码处理 LESS 代码 也可以在服务器上对其进行预处理 使浏览器只接收最终的 CSS
在 ASP NET MVC 中设置 LESS我将演示从 ASP NET MVC 应用程序中使用 LESS 所需的操作 首先 我将重点介绍 LESS 代码的客户端处理 在布局文件的 HEAD 部分添加以下内容
<link rel= stylesheet/less type= text/css href= @Url Content( ~/content/less/mysite less ) /><script type= text/javascript src= @Url Content( ~/content/scripts/less min js ) ></script>
这里假设您已在项目中创建了 Content/Less 文件夹以包含所有 LESS 文件 您需要一个 JavaScript 文件 以便在浏览器中进行实际的 LESS 到 CSS 处理 您可以从 获取该脚本文件 我将回顾一些可证明 LESS 有用的场景
运行中的 LESS 变量
观察 CSS 渐变是了解 LESS 变量作用的好方法 多年以来 设计人员使用小的 GIF 文件绘制 HTML 容器的渐变背景 最近 浏览器增加了 CSS 渐变支持 这也是官方 CSS 标准的一部分 通过线性渐变语法及其变体实现 很遗憾 如果要确保尽量多的浏览器采用这种渐变 必须借助一些东西 如 图 中的代码
图 中的代码几乎不可读 更糟的是 在需要渐变的任何地方都必须重复使用这些代码 此外 如果要稍微更改一下渐变颜色(或只更改饱和度或淡化效果) 唯一的办法是在所有位置进行手动编辑 直截了当地说 这非常困难 但是 这是对于普通 CSS 唯一可行的方法
图 在多种浏览器中显示渐变的综合代码
/* Old browsers fallback */ background color: #ff background: url(images/red_gradient png)background repeat: repeat x/* Browser specific syntax */ background: moz linear gradient( left #fceabb % #fccd d % #f b % #fbdf %)background: Webkit linear gradient( left #fceabb % #fccd d % #f b % #fbdf %)background: o linear gradient( left #fceabb % #fccd d % #f b % #fbdf %)background: ms linear gradient( left #fceabb % #fccd d % #f b % #fbdf %)/* Standard syntax */ background: linear gradient( to right #fceabb % #fccd d % #f b % #fbdf %)
为找到更好的解决方案 您需要跳出 CSS 试试 LESS 在 LESS 中 您只需定义一次渐变 CSS 然后在适当的位置按名称引用即可 例如
background gradient orange { background: #fceabb } &ntainer { background gradient orange}
名为 background gradient orange 的类按名称在适当的位置嵌入到类容器和任意其他类中 而渐变定义保存在一个位置
从开发人员的角度来看 这并不是什么革命性的改变 不过 它使用了变量功能 这是 CSS 中没有的 事实上 如果将文件保存为普通样式表并引用的话 前面的语法并不可行 需要一些代码将扩展语法转换为普通 CSS 这正是 LESS JavaScript 分析器的功能 它将变量扩展为其实际 CSS 内容
变量还适用于颜色或大小等标量值 请考虑以下 LESS 代码
@black: # #main { color: @black} header { background color: @black}
分析器将 @black 变量扩展为分配的值并进行全文件替换 最终效果是 在一处更改实际颜色 整个文件中的相应内容会自动更改 运行中的 LESS Imports
如果需要 您可以将 LESS 代码拆分到多个文件 引用文件和包含的类中 例如 假设您创建一个 gradients less 文件 内容如下
background gradient orange { background: #fceabb }
在另一个 LESS 文件中 如 main less 您可以通过导入该文件引用任何渐变
@import "gradients" &ntainer { background gradient orange}
如果 gradients less(扩展名不是严格必需的)位于其他文件夹中 则应在调用中指示路径信息以便导入 LESS Mixin
我调用该 LESS 项目进行变量渐变 严格来说 这并不完全正确 在 LESS 中 一个变量包含一个单一值 一个 CSS 类容器被称为一个 mixin 这类似于函数 但不包含任何自定义逻辑 就像函数一样 LESS 可以接受和处理参数 请看看图 中演示 mixin 的代码
在图 中 一个名为 shadow 的 mixin 定义了框阴影样式 并将颜色作为外部参数公开 与之类似 text box mixin 定义输入字段的基本外观 它导入阴影定义并保持宽度为参数化形式 通过这种方式 为不同大小(mini normal 和 large)的输入字段定义三个类就非常简单了 更重要的是 它只需进行少量编辑工作 更新也非常简单(请参阅图 )
图 LESS Framework 中的 Mixin
/* Mixins */ shadow(@color) { box shadow: px px px @color } text box(@width) { shadow(# ) border: solid px # background color: #dddd padding: px width: @width } /* CSS classes */ text box mini { text box( px) } text box normal { text box( px) } text box large { text box( px) }
图 运行中的 LESS Mixin
Mixin 可以接受多个参数或可变数量的参数 此外 每个参数都支持默认值
mixin(@color: #ff ) { }
LESS 并不是富编程语言表示 它的设计缺少命令来指示条件或循环 但 mixin 的行为仍然可以根据所传递的值发生变化 假设您要对一个较大的按钮使用较粗的边框和字体 您定义一个名为 button 的参数化 mixin 使用关键字 when 将设置与条件绑定 条件必须基于一个参数
button (@size) when (@size <px) { padding: px font size: em width: @size * } button (@size) when (@size >= px) { padding: px font size: em font weight: background color: red width: @size * }
您应用不同的设置 但也可以使用基本操作通过一个系数将大小扩大为数倍 然后在实际 CSS 类中使用 mixin
push button large { button( px) } push button *** all { button( px) }
运行此代码的结果如 图 所示
图 在 CSS 类中使用 LESS Mixin 的效果
LESS 附带很多可操作颜色的预定义函数 您可以使用函数按百分比调整颜色亮度和饱和度 也可以按百分比设置颜色淡入和淡出 如下所示
push button { background color: fade(red %) }
有关 LESS 支持的函数的完整文档 请参阅 嵌套类
我个人觉得需要重复 CSS 块指示同级样式非常讨厌 下面是一个典型示例
#container h { } #container p { } #container p a { } #container img { }
在编写得很好的普通 CSS 中 实际上可以避免很多重复 但使用平面列表布局样式的方式并不是最好的 在这种情况下 最好使用一些层次结构 在 LESS 中 可以像这样嵌套样式规则
&ntainer { h { font size: em color: fade(# %) a { color: # &:hover {color: red} } } }
经过处理后 前面的 LESS 代码会产生下面的样式
&ntainer h &ntainer h a &ntainer h a:hover
服务器端处理
您可以原样下载 LESS 代码 在客户端通过 JavaScript 代码对其进行处理 也可以在服务器上进行预处理 然后将它作为普通 CSS 下载到客户端 在前一种情况下 完全像使用普通 CSS 文件一样 服务器端更改在下一次页面刷新时应用到客户端
如果您注重性能 处理的是大型复杂 CSS 文件 则服务器端预处理可能是更好的选择 服务器端预处理发生在您每次修改服务器上的 CSS 时 您可以在生成过程结束时手动完成额外的步骤 使用 LESS 编译器从命令行将 LESS 代码预处理为 CSS 此编译器是为服务器端工作安装的 less NuGet 软件包的一部分
不过 在 ASP NET MVC 中 可以将 LESS Framework 与捆绑机制集成 有关捆绑机制 请参阅我在 年 月的专栏 CSS 编程 捆绑和缩小 (msd/magazine/dn ) 这确保只要请求 LESS 文件 就会执行 LESS 到 CSS 的转换 还确保通过 If Modified Since 标头正确管理缓存 最后 您可以将分析和缩小混合起来 要在 ASP NET MVC 中集成 LESS 首先需要下载并安装 less NuGet 软件包 然后将以下代码添加到 BundleConfig 类
var lessBundle = new Bundle("~/myless") IncludeDirectory("~/content/less" "* less") lessBundle Transforms Add(new LessTransform()) lessBundle Transforms Add(new CssMinify()) bundles Add(lessBundle)
捆绑将打包在指定文件夹中找到的所有 less 文件 LessTransform 类负责 LESS 到 CSS 的转换 该类使用 less API 分析 LESS 脚本 LessTransform 的代码非常简单
public class LessTransform : IBundleTransform { public void Process(BundleContext context BundleResponse response) { response Content = dotless Core Less Parse(response Content) response ContentType = "text/css" } }
更多智能工具
lishixinzhi/Article/program/Web/201404/30643