CSS 彻底改变了 Web 页面的设计,但 CSS 仍然是静态的,而且在其句法发展方面受到限制。这些限制是有目的且合乎情理的,鼓励广泛加以实现。但开发人员和设计人员常常发现 CSS 使用起来很单调乏味。许多 Web 框架包含一些工具,这些工具使得人们更容易使用更灵活的特性创作 CSS,然后将结果编译成静态 CSS,以便部署到站点。最近的一些项目更侧重于创建旨在编译到 CSS 中的语言。Alexis Sellier 的开源项目 LESS 是这类语言中最受欢迎的一种语言。
LESS 在现有 CSS 语法之上添加了一些开发人员熟悉的特性,比如变量、mixins、运算符和函数。可以使浏览器中的 JavaScript 或通过服务器端 JavaScript 工具集的预处理将 LESS 编译到 CSS 中。LESS 在其他各种工具集中也得到了广泛应用,包括 JavaScript 的流行 Bootstrap 项目。在本文中,我要介绍的是 LESS(尤其是 1.4 版本),LESS 是为现代网站编写可读性的、可维护的 CSS 的一种方式。参见 下载部分,获取本文的示例代码。
入门
下载最新版 LESS(撰写本文之时是 1.4;参见 参考资料)。然后准备学习其语言。万维网联盟 (W3C) 在其维基中提供了一些用于学习 CSS 的资料。我基本上遵循该教程的顺序,因此,如有需要的话,您可以一前一后学习基本的 CSS 和 LESS。
清单 1 再现了 W3C 教程的第一个示例:
清单 1. 基本 CSS 示例 (listing1.css)
1 2 3 4 5 |
p { color: red; font-size: 12px; background-color: green; } |
清单 2 中的 HTML 将 清单 1 中的 CSS 投入使用:
清单 2. 引用清单 1 的基本 CSS 示例的 HTML (listing2.html)
1 2 3 4 5 6 |
<head> <link rel="stylesheet" type="text/css" href="listing1.css"> </head> <body> <p>This is a paragraph</p> </body> |
图 1 显示了 Mac OS X 上 Safari 浏览器中显示的 listing2.html:
图 1. 使用清单 1 中的 CSS 的浏览器输出
删除魔法值
看到 清单 1 的开发人员很可能立刻注意到那些违反开发者本能的内容,即硬编码到 CSS 中的值,这些值有时被揶揄为 “魔法值 (magic value)”。LESS 中最重要的特性之一是变量。清单 3 是使用变量的一个 LESS 基本示例版本:
清单 3. 使用 LESS 中的变量的基本 CSS 示例 (listing3.css)
1 2 3 4 5 6 7 8 9 |
@main-text-color: red; @main-text-size: 12px; @main-text-bg: green; p { color: @main-text-color; font-size: @main-text-size; background-color: @main-text-bg; } |
清单 3 不是语法正确的 CSS,因此您不能在 HTML 中将 listing1.css
替换为 listing3.less
。您还必须更新主机 HTML 来调用 JavaScript 编译器,如清单 4 所示:
清单 4. 引用基本 CSS 示例 LESS 版本的 HTML (listing4.html)
1 2 3 4 5 6 7 |
<head> <link rel="stylesheet/less" type="text/css" href="listing3.less"> </head> <body> <p>This is a paragraph</p> <script src="less.js" type="text/javascript"></script> </body> |
请注意,在 清单 4 中,我将 script
标记放在页面 body
的结尾处。传统上,大多数开发人员将 script
标记放在 head
中。但将它们放在 body
中是合法的,这利用了这样一个事实(引用自 HTML 4 规范),即 “script
元素按照加载文档的顺序进行求值”。如今许多站点在临近结束时都有一些脚本,因此主要内容的加载不会因为任何脚本处理而延迟。
服务器端编译
到目前为止,我已经向您展示:开发和部署 LESS 便于快速使用浏览器,但却是有代价的。每次页面加载时,编译用的 JavaScript 都运行于用户的浏览器之上,这耗尽了计算资源并减缓了页面加载。如果在浏览器中加载 清单 4 ,并检查 JavaScript 控制台,则会看到一条消息:“less: css generated in 36ms”。36 毫秒的时间并不算长,但它代表着额外的不必要计算和时间。快速页面加载在 Web 上很重要。
在转入生产模式之后,使用一个服务器端 JavaScript 工具将 LESS 编译到 CSS 中。Node.js 是一个流行选项,被记录在 LESS 站点上。我喜欢使用 Mozilla 的独立 JavaScript 项目 Rhino。要使用 Rhino 和 LESS,请下载并安装 Rhino(参见 参考资料)。将 js.jar 放在一个方便进行构建的位置。您需要一个特殊版本的 less.js,该版本可在 GitHub 完整下载的 LESS 中下载中找到(参见 参考资料)。本文中使用的版本是 less.js-master/dist/less-rhino-1.4.0.js。将 less-rhino-1.4.0.js 放在保存 Rhino JAR 的地方。下面准备将 LESS 代码编译到 CSS 中。
要编译 listing3.less,请切换到 listing3.less 所在的目录并执行以下命令:
1 |
java -jar js.jar less-rhino-1.4.0.js listing3.less > listing3.css |
编译操作会将生成的 CSS 放在 listing3.css 文件中。该文件的内容如下:
1 2 3 4 5 |
p { color: #ff0000; font-size: 12px; background-color: #008000; } |
在 listing3.css 中,LESS 变量被替换,颜色名称被替换为 RGB 形式(比如 red
被替换为 #ff0000
)。现在您可以按照常用方法将 listing3.css 部署到一台服务器中。
LESS 替代注释语法
LESS 的一个小小的增强是,编写单行注释的方式变得简单了。清单 5 显示了来自 W3C CSS 教程的一个标准注释示例:
清单 5. 使用注释的 CSS 示例 (listing 5.css)
1 2 3 4 5 |
p { color: red; /* This is a comment */ font-size: 12px; } |
清单 6 中的 LESS 代码等同于 清单 5 :
清单 6. 与使用简化注释的清单 5 等同的 LESS 代码 (listing6.less)
1 2 3 4 5 |
p { color: red; // This is a comment font-size: 12px; } |
清单 6 使用的语法对于程序员来说很常见,而且键入起来稍微容易一些。但鉴于处理 LESS 的方式,这种注释并不出现在生成的 CSS 中。如果您想为浏览器查看器保留注释(例如用于版权声明),则必须使用标准的 CSS 注释语法。
W3C 教程其余内容专注于 CSS 选择器语法和常见属性的细节。此时,我要将重心转向 LESS 的更广泛使用,这是大多数 Web 开发人员在实践过程中越来越多遇见的情形。
创建响应式设计
在 2010 年,许多 Web 设计人员开始倡导一种称为 响应式设计 的页面设计方法。从一开始,就需要构建灵活的 Web 页面,在从小型手机到比常用台式机更大的显示设备中查看它们。
响应式设计的核心是 CSS3 媒体查询,该查询是一种根据用户显示器的性质(特别是尺寸)来调用 CSS 规则的标准方式。LESS 使我们能够更容易地展现使用媒体查询来实现响应式设计的 CSS。出于演示之目的,我将 developerWorks 博主 Bob Leah 的优秀响应式设计 示例 的一个 LESS 版本组合起来。在文章的代码包(参见 下载)中,它是 responsive.less。
运算符
responsive.less 中的一项关键技术是使用变量设置基本的方框大小,然后根据可视区的大小调整方框。我使用 LESS 运算符来进行缩放。例如,清单 7 中的代码段使用乘法运算符来缩放横幅图像:
清单 7. LESS 中乘法的使用
1 2 3 4 |
#banner img { max-width: (@bannerwidth * @scale); max-height: (@mainheight * @scale); } |
在 清单 7 中,@bannerwidth
和 @mainheight
是根据 @scale
因子缩减的默认值。最新的 LESS 版本要求您将包含运算符的所有表达式放在圆括号中,以避免语法混淆。
嵌套规则
LESS 最有用的功能之一是嵌套 CSS 规则。嵌套规则有助于您以简单易懂的方式组织代码。在清单 8(responsive.less 中的一段经过修改的摘录片段)中,我在媒体查询内嵌套了通用的 CSS 规则:
清单 8. LESS 中嵌套规则的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@media (min-width: 401px) and (max-width: 800px) { @scale: 0.75 #banner { width: (@bannerwidth * @scale); } #banner img { max-width: (@bannerwidth * @scale); max-height: (@mainheight * @scale); } #main { width: (@mainwidth * @scale - @extrabuffer); } #main-content { width: (@maincontentwidth * @scale * 0.75 - @extrabuffer); float: left; } } |
清单 8 中的嵌套规则等同于清单 9 中多个独立的 CSS 规则:
清单 9. 等同于清单 8,但无嵌套规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@scale: 0.75 @media (min-width: 401px) and (max-width: 800px) and #banner { width: (@bannerwidth * @scale); } @media (min-width: 401px) and (max-width: 800px) and #banner img { { max-width: (@bannerwidth * @scale); max-height: (@mainheight * @scale); } @media (min-width: 401px) and (max-width: 800px) and #main { width: (@mainwidth * @scale - @extrabuffer); } @media (min-width: 401px) and (max-width: 800px) and #main-content { width: (@maincontentwidth * @scale * 0.75 - @extrabuffer); float: left; } |
清单 9 中的版本没有提供这些密切相关规则的自然分组,而且还因为反复指定媒体查询而违反了 DRY(不要重复自己)原则。
mixins
LESS 减少重复的另一种方式是让您指定可添加到其他规则中的一组规则。在 responsive.less 中,我使用了此 mixin 技术来跨两个不同的媒体查询表达常见规则,如清单 10 所示:
清单 10. LESS 中 mixins 的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
.media-body (@scale: 0.75) { #banner { width: (@bannerwidth * @scale); } #banner img { max-width: (@bannerwidth * @scale); max-height: (@mainheight * @scale); } #main { width: (@mainwidth * @scale - @extrabuffer); } #main-content { width: (@maincontentwidth * @scale * 0.75 - @extrabuffer); float: left; } #widget-container { width: (@widgetoutwidth * @scale * 0.75 - @extrabuffer); float: right; } .widget-content { width: (@widgetinwidth * @scale * 0.75 - @extrabuffer); } } //Rules for viewing from 401px to 800px @media (min-width: 401px) and (max-width: 800px) { .media-body; } //Rules for viewing smaller than 400px @media (max-width: 400px) { .media-body(0.3); //Extra manipulation of some rules #main-content { padding: 0px; } #widget-container { width: padding: 0px; } .widget-content { margin: 5px; } .widget-text { display: none; } } |
Mixins 可以接受参数,比如 清单 10 中方框大小的比例因子。默认的比例因子是 0.75
。清单 10 在可视区中使用从 401px 到 800px 的默认大小。为了在小于 400px 的尺寸下进行查看,比例因子被更改为 0.3
,并且在该区域添加了一些额外规则。
图 2 显示了 responsive.html 的浏览器显示,它使用了 responsive.less。我减小了浏览器的宽度,以满足小于 400px 的宽度的媒体查询,这样一来您就可以看到页面在小型移动设备上是什么样子。
图 2. responsive.html 的低宽度浏览器输出
在我 Mac 上的 Safari 中,当浏览器宽度接近 500px 时,小于 400px 的宽度的媒体查询被触发。该行为引出了一个重要观点。媒体查询基于视区 这一概念。视区是可视浏览器空间的数量,用 CSS 像素进行定义,并通过设备和浏览器进行确定。CSS 像素不同于设备像素;例如,如果用户缩放浏览器视图,那么像素模型之间的关系就会发生变化(参见 参考资料)。此外,设备和浏览器设置的视区大小不同于实际显示的窗口大小。在 图 2 中就是如此:窗口大约是 500px,但 CSS 将其作为 400px 宽的视区加以处理。这一现象强调了这样一个事实:与所有 Web 开发技术一样,响应式设计需要完善的跨设备测试。
结束语
我是一名软件架构师兼开发人员,但绝不是一名 Web 设计人员。凭借 LESS,我可以利用我的编程技能快速开发更便于理解和维护的 CSS。变量和 mixins 使我能够快速做出调整,查看其效果,无需在整个 CSS 文件内四处移动,查找我需要进行相关更改的内容。
响应式设计是经济适用的可管理移动 Web 设计中的一项公认的关键技术。它在针对打印等可访问性和其他演示模式的设计中也很有用。由于为应对媒体查询而应用的多种样式处理起来很繁琐,所以 LESS 简化和组织 CSS 代码的功能愈发有价值。