前言:MDN上有写关于如何高效的css的文章,此文主要参考其做了记录(也可以理解为是翻译)。
css规范并不会强行规定浏览器必须如何实现样式系统,只会规定浏览器必须实现什么。因此,不同的样式系统引擎拥有不同的性能,开源的 Gecko和Webkit算法类似,因此优缺点也类似。因此,下面的建议在大部分的web浏览器上应该是有意义的。
第一部分简单介绍样式系统规则分类;后面的章节主要指导如何利用样式系统的实现原理,来书写更有效率的规则。
样式系统如何建立规则
样式系统的规则分为四大类
- ID
- class
- tag
- 通用规则
理解这四类规则非常关键,这是规则匹配的基础。
在接下来的段落中,我会使用"关键选择“(key selector)术语。key selector是选择器的最后一部分。
例如,在下面的规则中:
a img, div > p, h1 + title {...}
key selector是img,p和title。
ID rules
第一类是使用ID选择器作为key selector.
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 rules
第二类是使用了class选择器作为key selector
button.toolbarButton {…} /* A class-based rule */
.fancyText {…} /* A class-based rule */
menuitem > .menu-left[checked="true"] {…} /* A class-based rule */
Tag rules
如果既不是class也不是ID作为key selector,下一个候选是tag。
td {…} /* A tag-based rule */
treeitem > treerow {…} /* A tag-based rule */
input[type="checkbox"] {…} /* A tag-based rule */
Universal rules
剩下的均为此类。
[hidden="true"] {…} /* A universal rule */
* {…} /* A universal rule */
tree > [collapsed="true"] {…} /* A universal rule */
样式系统如何匹配规则
样式系统从key selector开始匹配,然后向左继续,寻找选择器的任意祖先。只要选择器的子树继续导出(这样翻译感觉怪怪的),样式系统会继续往左移动,直到要么匹配规则,要么因为不匹配终止。
最基本的概念是了解规则过滤。这些类别存在的目的是过滤掉不相关的规则,这样样式系统不用浪费时间去匹配它们。
这是提升性能的关键:检查一个指定的元素,规则越少,系统解析就越快。
例如,如果元素指定了ID,那么只有与元素ID相同的ID rule会进行检查。只有存在于元素class列表的class 规则才会进行检查。只有与标签相同的tag rule会被进行检查。通用规则总是会被检查。
高效css建议
避免使用通用规则
避免一个规则的结束是通用规则这一类。
不要使用tag或者class修饰ID rule
如果一个规则使用了ID选择器作为key selector,不要再添加tag标签指定。因为ID是唯一的,增加tag name会增加不必要的额外的匹配工作。
BAD
button#backButton {…}
BAD
.menu-left#newMenuIcon {…}
GOOD
#backButton {…}
GOOD
#newMenuIcon {…}
例外:当需要通过改变元素的class来应用不同的样式,但是同样的class将会被其他元素共享。
不要使用tag修饰class规则
尽管class可以在同一个页面重复出现,但是它的唯一性比tag更强。
你可以约定在class名称中包含tag名称,但是这会损失一些灵活性。当设计改变tag时,class也会跟着变化。最好的是使用语义名称的class name。
BAD
treecell.indented {…}
GOOD
.treecell-indented {…}
BEST
.hierarchy-deep {…}
使用最特定的一类规则
tag这类会匹配太多的规则,这会大大的降低效率。通过给元素增加class,我们可以回class分类进行细分,减少匹配时间。
BAD
treeitem[mailfolder="true"] > treerow > treecell {…}
GOOD
.treecell-mailfolder {…}
避免使用后代选择器
后代选择器是css中最耗时的选择器。尤其当选择器是tag或者通用这一类。
BAD
treehead treerow treecell {…}
BETTER, BUT STILL BAD (see next guideline)
treehead > treerow > treecell {…}
tag分类规则永远不要包含孩子选择器
避免使用孩子选择器在tag分类规则中。这会显著增长匹配时间。
BAD
treehead > treerow > treecell {…}
GOOD
.treecell-header {…}
质疑所有使用孩子选择器的地方
使用孩子选择器时务必谨慎,尽可能避免使用。
特别是,子选择器频繁适用于RDF树(这个自行Google吧)和menus,如下:
BAD
treeitem[IsImapServer="true"] > treerow > .tree-folderpane-icon {…}
依靠继承
了解哪些属性继承,然后使用继承。
BAD
#bookmarkMenuItem > .menu-left { list-style-image: url(blah) }
GOOD
#bookmarkMenuItem { list-style-image: url(blah) }
Use -moz-image-region
这条个人感觉不靠谱
Use scoped stylesheets
这条个人感觉不好维护
除非必要,不要使用特定浏览器特性
这条个人感觉意义不大
推荐阅读:
MDN Writing efficient CSS
Performance improvement by writing efficient CSS selector