Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

编写高效的 CSS

这篇文章需要技术复核。如何帮忙。

这篇文章需要文法复核。如何帮忙。

本文档提供了优化 CSS 代码的指南,特别是如何编写更高效的选择器。

CSS规范并没有明确浏览器如何去实现样式系统,仅仅是说明了它们必须这样做。有鉴于此,不同的样式系统引擎可能会拥有完全不同的表现和行为,特别是 Gecko 与 WebKit, 这两个引擎都是开源项目,实现了类似的算法,具有极其相近的优缺点。因此下面介绍的小技巧对于真实世界的 Web 文档将会十分有用。

第一部分内容综合讨论了常见的样式系统是如何分类规则的。接下来的部分包含了书写规则的指南,它利用了前面讨论的样式系统的优点。

样式系统如何拆分规则

样式系统将规则拆分成四个主要类别:

  1. ID 规则
  2. Class 规则
  3. 标签规则
  4. 通用规则

理解这些分类是十分关键的,因为它们是构建规则匹配块的基础。

我在下面的段落中使用术语 关键选择器(key selector)。选择器的最后面的部分即为关键选择器(即用来匹配目标元素的那部分,而不是该元素的祖先元素)。

例如,在下面规则中…

a img, 
div > p, 
h1 + [title] {
  …
}

关键选择器为 img、 p 和 title.

ID 规则

这第一个类别包含了那些将 ID 选择器作为关键选择器的规则。

示例
button#backButton {…} /* This is an ID-categorized rule */
#urlBar[type="autocomplete"] {…} /* This is an ID-categorized rule */
treeitem > treerow > treecell#myCell:active {…} /* This is an ID-categorized rule */

Class 规则

如果一个规则将一个 class 明确作为它的关键选择器,那么它就属于该类别。

示例
button.toolbarButton {…} /* A class-based rule */
.fancyText {…}	/* A class-based rule */
menuitem > .menu-left[checked="true"] {…} /* A class-based rule */

标签规则

如果既没有 class 也没有 ID 来明确作为关键选择器,那么接下来的候选者就是 标签 类别。 如果一条规则将一个标签作为它的关键选择器,那么这条规则就属于该类别。

示例
td {…} /* A tag-based rule */
treeitem > treerow {…} /* A tag-based rule */
input[type="checkbox"] {…} /* A tag-based rule */

通用规则

不属于上面那些类别的规则都属于这个类别。

示例
[hidden="true"] {…} /* A universal rule */  
* {…}		/* A universal rule */
tree > [collapsed="true"] {…} /* A universal rule */

样式系统如何匹配规则

样式系统从关键选择器开始匹配规则,然后左移(查找规则选择器的任何祖先元素)。只要选择器的子树(substree)一直在检查,样式系统就会持续左移,直到和规则匹配,或者是因为不匹配而放弃该条规则。

规则过滤是你需要学习的最基础的概念。分类存在的意义就是过滤掉无关的规则(这样样式系统就不会浪费时间去匹配它们了)。

这就是能够极大提高性能的关键。对于一个给定的元素,需要匹配的规则越少,样式的解析就会越快。

举个例子,如果一个元素拥有一个 ID,那么只有匹配该 ID 的 ID 规则才会被选中。同理,只有当 Class 规则中的 class 出现在元素上时该规则才被检查。只有当标签规则的标签匹配时该规则才被检查。通用规则始终都会检查。

高效 CSS 指南

避免通用规则

请确保规则不以通用类型选择器作为结束!

不要用标签名或 classes 来限定 ID 规则

如果规则拥有 ID 选择器作为其关键选择器,则不要为规则增加标签名。因为 ID 是唯一的,增加标签只会没必要地减缓匹配过程。

button#backButton {…}
.menu-left#newMenuIcon {…}
#backButton {…}
#newMenuIcon {…}
例外:在不同的场景下,要动态改变元素的class,从而应用不同的样式,这是可取的。但是这个相同的class是与其他元素所共享的。

不要用标签名限定 class 规则

前面那节内容在这里同样适用。虽然在同一页面能够多次使用 class,但它仍然比标签名更独特。

按照惯例,你可以将标签名包含在 class 名。但是,这会有损灵活性;如果设计更改以至于要变更标签,这条class 名也必须跟着变动。(最好的办法是选择严格语义化的名字,毕竟分离样式表的一个目标就是为了灵活性。)

treecell.indented {…}
.treecell-indented {…}
.hierarchy-deep {…}

尽量使用最具体的类别

解析速度变慢的罪魁祸首就是标签类别中有过多的规则。通过增加 class 到元素上,我们就可以进一步的将这些规则划分到 Class 类别中,这将减少用于匹配标签的时间。

treeitem[mailfolder="true"] > treerow > treecell {…}
.treecell-mailfolder {…}

避免后代选择器

后代选择器是 CSS 中性能耗用最大的选择器。 它是性能开销相当大的——特别是当选择器在标签或通用类别中。

通常我们需要的是 子选择器。比如说,当性能十分差的时候,Firefox 的用户界面CSS 将毫无理由的禁止掉后代选择器。你也应该在网页中这么做。

treehead treerow treecell {…}
略好,但还是差(查看下一条指南)
treehead > treerow > treecell {…}

标签分类的规则不要包含子选择器

标签类别的规则中避免使用子选择器。否则的话,在该元素出现的所有地方,匹配时间都将极大延长(特别是当规则很可能会被匹配)。

treehead > treerow > treecell {…}
.treecell-header {…}

在使用子选择器的地方想想为什么

当使用子选择器时要十分谨慎。能免则免。

特别来说,子选择器常常用于 RDF 树与菜单:

treeitem[IsImapServer="true"] > treerow > .tree-folderpane-icon {…}

要记住,模板中的 REF 特性可以重复出现!好好利用这一优点。在子 XUL 元素上重复使用 RDF 属性,这样可以基于该属性来修改元素。

GOOD
.tree-folderpane-icon[IsImapServer="true"] {…}

依赖继承

了解哪些属性能够继承,然后允许它们这样做!

例如,XUL组件会明确的设置,使得父级元素的列表样式图像或字体规则衍生到匿名内容。因而没有必要去在匿名内容上直接应用规则浪费时间。

#bookmarkMenuItem > .menu-left { list-style-image: url(blah) }
#bookmarkMenuItem { list-style-image: url(blah) }

在以上示例中,要为匿名内容应用样式(不利用 list-style-image 的继承特性),将会产生Class分类中的规则,当这条规则本应该止于ID分类——所有分类中最确切的分类。

谨记: 所有元素都有同一种class,尤其是匿名内容!

上面示例中的“差”规则强制每个菜单的图标都要在包含书签的菜单项内进行测试。因为这里有很多菜单,这将是极其耗费的。相反,这条“好”规则将测试限制在书签菜单(外围容器,非单独项)内。

使用 -moz-image-region

如果你正在开发针对Mozilla的代码:将一系列图像放置在一个单独的文件中,然后使用 -moz-image-region 进行选择,这比将他们分别放在自身的文件中来选择要表现得更加良好。

使用局部样式表

如果你能够明确将样式表作为XBL源,这些样式仅仅应用在被绑定的元素和其中的匿名内容上。这会减小通用规则和子元素选择器带来的负面影响,因为他们考虑的元素会更少。

如非必要则避免特定浏览器的渲染特征

总有有一些针对特定浏览器的或者实验性的标签和CSS属性,他们以前缀的形式来区分能够起作用的浏览器,例如 -webkit、-moz、 -ms、-o 等等。一旦某个标签或属性被标准化,这些前缀属性就会被移除。举个例子,在 border-radius 被标准化和被所有主流浏览器实现之前,你必须使用 -webkit-border-radius-moz-border-radius 等属性。

对特定渲染的前缀和标签及属性的标准化的变化保持意识,并且在任何可行的时间都要去避免使用任何特定渲染的特性。

源文档信息

文档标签和贡献者

 此页面的贡献者: Serifx, gentleTiger, ziyunfei, ReyCG_sub, teoli, sunnylost
 最后编辑者: Serifx,