在Mozilla UI中优化CSS文件的规则
以下文档描述了应用在MozillaUI中优化CSS文件的规则。第一部分是对于Mozilla样式系统分类规则的一般性讨论。在了解这个系统的基础上,后续部分包含了一些指南,书写可以利用这个样式系统实践优点的样式的指南。
样式系统如何分类规则
样式系统把规则分为四大类。理解这些类是很重要的,因为对于规则的匹配来说他们是首先要考虑的。之后的段落中会使用“主选择符”这个说法。主选择符是指选择符最右边的部分(最终要匹配的那个元素,而不是它的祖先元素)。例如,在以下规则中:
aimg,div>p,h1+[title]{}
主选择符是“img”,“p”,和“[title]“。
ID规则
ID选择符作为主选择符的规则。
例如:
button#backButton{}/*ID类别的规则*/
#urlBar[type="autocomplete"]{}/*ID类别的规则*/
treeitem>treerow>treecell#myCell:active{}/*ID类别的规则*/
Class规则
如果一条规则有一个指定的class作为主选择符,就被归入此类。
例如:
button.toolbarButton{}/*基于class的规则*/
.fancyText{}/*基于class的规则*/
menuitem>.menu-left[checked="true"]{}/*基于class的规则*/
Tag规则
如果主选择符不是ID或者class,那么下一个类很可能就是tag分类。如果一条规则指定tag为主选择符,就被归入此类。
例如:
td{}/*基于tag的规则*/
treeitem>treerow{}/*基于tag的规则*/
input[type="checkbox"]{}/*基于tag的规则*/
全局规则
除以上分类之外都归入此类。
例如:
[hidden="true"]{}/*全局规则*/
*{}/*全局规则*/
tree>[collapsed="true"]{}/*全局规则*/
样式系统如何匹配规则
样式系统从最右边的选择符开始向左侧移动来匹配一条规则。样式系统会一直向左匹配选择符直到规则匹配完毕或者由于出错停止匹配。
对于规则分类的第一步发生在主选择符类别基础上。这个分类的目的是把那些不需要浪费时间匹配的规则过滤出来。这是显著提升性能的重点。对于一个给定的需要匹配的元素,规则越少,样式的渲染越快。例如,元素有一个ID,那么只有和元素ID匹配的ID规则会被检索。只有和元素的class匹配的class规则会被检索。只有和tag匹配的tag规则会被检索。全局规则总是会被检索。
高效CSS指南
避免全局规则
确保规则不以全局分类结束
不要给ID分类规则指定标签名或者class
如果有一条样式规则是以ID选择符为主选择符的,就别再画蛇添足的加上标签名了。ID都是唯一的,因此加上标签名反而会无谓地拖慢匹配过程。(当有不同元素使用同一类名,而又需要动态地改变其中一个元素的类名来针对不同情况应用不同样式时是个例外。)
BAD–button#backButton{}
BAD–.menu-left#newMenuIcon{}
GOOD–#backButton{}
GOOD–#newMenuIcon{}
不要给class分类规则指定标签名
和以上规则类似,所有的类名也是唯一的。标签和类名连缀的写法是一个惯例(但是,如果设计的变更使得需要改变标签就会有灵活性的问题,因为也需要改变class—最好选用具有严格语义的名字,这种灵活性也是分离样式表的目标之一)。
BAD–treecell.indented{}
GOOD–.treecell-indented{}
BEST–.hierarchy-deep{}
尽量把规则应用到最明确的类上。
拖慢系统最大的一个原因是有太多的tag分类规则了。通过给元素增加类名,可以把这些tag类里的规则分一部分去class分类,就可以不需要浪费时间来试图给一个标签匹配那么多的的规则了。
BAD–treeitem[mailfolder="true"]>treerow>treecell{}
GOOD–.treecell-mailfolder{}
避免后代选择符
CSS中,后代选择符(descendant)[注1]的耗能高的可怕,尤其是选择符的规则是在tag或者全局分类中。子选择符(childselector)则经常是真正所需。如果没有主题模块所有者的明确允许,UICSS中禁止使用后代选择符。
BAD–treeheadtreerowtreecell{}
BETTER,BUTSTILLBAD(seenextguideline)–treehead>treerow>treecell{}
Tag类规则中最好不要包含后代选择符
避免使用具有tag类规则的后代选择符。这会明显地增加匹配时间(尤其是这些规则会被多次匹配时)。
BAD–treehead>treerow>treecell{}
BEST–.treecell-header{}
小心子选择符的使用
要小心使用子代选择符。如果有别的方式可以不用,就不要用子选择符。尤其是子选择符被大量使用在RDF树和类似的菜单中时。
BAD–treeitem[IsImapServer="true"]>treerow>.tree-folderpane-icon{}
要注意模版中来自RDF的属性是可以复制的!可以利用这一点把RDF属性复制到需要改变那个属性的子元素上。
GOOD–.tree-folderpane-icon[IsImapServer="true"]{}
倚赖继承
了解并使用那些可以继承的属性。XULwidgetry[注2]已经明确设置了,因此可以把list-style-image或者font规则应用到父级标签上,它将渗透进匿名内容。因此就不需要浪费时间为那些匿名内容写规则了。
BAD–#bookmarkMenuItem>.menu-left{list-style-image:url(blah);}
GOOD–#bookmarkMenuItem{list-style-image:url(blah);}
上例中,样式化匿名内容的需求(没有理解list-style-image可以继承)导致了一条class类规则。其实这条规则应该属于最明确的一类—ID类规则。
要记住,尤其是那些匿名内容,它们都有同样的class。上面那个不好的例子导致需要检查每个菜单的图标是否包含在bookmarks菜单项中。这是非常可怕的高昂消耗(有很多菜单);除bookmarks菜单之外,这条规则不应该被其他任何菜单想检查。
使用-moz-image-region
把一堆图片放到一个单独的图片文件中,并用-moz-image-region[注3]选中会有显著的性能提升。()
注1:后代选择符(descendantselector)子选择符(childselector)是有区别的。单从字面来讲,后代选择符,顾名思义包括儿子、孙子、重孙子等所有后代;子选择符只是指儿子,就不管那帮孙子了。
注2:XULwidgetry不清楚是啥。
注3:貌似想法和现在说的CSSsprites方法差不多,要知道这可是十年前(2000年)的文章啊。–糖伴西红柿