文章目录
  1. 1. 浏览如何识别选择器?
  2. 2. 如何写有效率的CSS选择器?
    1. 2.1. 选择器效率排序
    2. 2.2. 一些写高效CSS选择器的规则
      1. 2.2.1. 不要在ID选择器前加标签名或类
      2. 2.2.2. 不要在类前加标签名
      3. 2.2.3. 尽可能使用最具体的类别
      4. 2.2.4. 避免使用后代选择器
      5. 2.2.5. 标签分类规则不应该包含子元素选择器
      6. 2.2.6. 避免使用通配符选择器
      7. 2.2.7. 避免使用单规则的选择器
      8. 2.2.8. 避免使用类正则的选择器
      9. 2.2.9. 适当调整你的选择器
    3. 2.3. 笔者认为…

曾几何时,我天真的认为“选择器肯定是越详细,层数越多越好呗”。现在觉得自己以前真是图样图森破…
谨以此文,祭奠那些被我误用的CSS, orz。
此文重在讨论如何书写高效的CSS选择器。如有错误,欢迎指正,O(∩_∩)O


浏览如何识别选择器?

“浏览器读取选择器的顺序是由右到左进行”—《Efficiently Rendering CSS》Chris Coyier

例如:

1
ul > li a[title="home"] {…}

浏览器将首先解释 a[title=”home”]。这个最先解释选择器是最后被选择的元素的“关键选择器”。

再如:

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

此处关键选择器为 img,p,title

关键选择器示例:

1
2
3
4
5
6
7
8
#main-navigation {…} /* ID (Fastest) */
body.home #page-wrap {…} /* ID */
.main-navigation {…} /* Class */
ul li a.current {…} /* Class *
ul {…} /* Tag */
ul li a {…} /* Tag */
* {…} /* Universal (Slowest) */
#content [title='home'] {…} /* Universal */

越具体的关键选择器,其性能越高。

如何写有效率的CSS选择器?

选择器效率排序

选择器效率从高到低排列如下

  • id选择器(#myid)
  • 类选择器(.myclassname)
  • 标签选择器(div,h1,p)
  • 相邻选择器(h1+p)
  • 子选择器(ul > li)
  • 后代选择器(li a)
  • 通配符选择器(*)
  • 属性选择器(a[rel=”external”])
  • 伪类选择器(a:hover,li:nth-child)

一些写高效CSS选择器的规则

不要在ID选择器前加标签名或类

如果一个规则的关键选择器是ID选择器,不要在其前面加上标签名或类名。因为ID是唯一的加上一个标签名会降低匹配速度。

  • BAD
1
button#backButton {…}
  • GOOD
1
#backButton {…}
  • BAD
1
.menu-left#newMenuIcon {…}
  • GOOD
1
#newMenuIcon {…}

不要在类前加标签名

之前的观念依然适用,虽然类可在同个页面中被使用多次,但他们仍比标签稀罕。

  • BAD
1
div.indented {…}
  • GOOD (tag+class命名法 缺点是不够灵活,如果改了标签类名也要换)
1
.div-indented {…}
  • BEST (语义化的类名使其更灵活)
1
.hierarchy-deep {…}

尽可能使用最具体的类别

  • BAD (太多的规则导致查找速度变慢)
1
a[target=_blank] > p > span {…}
  • GOOD
1
.span-target-blank {…}

避免使用后代选择器

后代选择器是CSS中代价最昂贵的选择器。尤其是标签或是通配符选择器,它将昂贵的可怕。

  • BAD
1
table tbody tr th {…}
  • BETTER,BUT STILL BAD
1
table > tbody > tr > th {…}

标签分类规则不应该包含子元素选择器

避免在标签类型规则使用子元素选择器。这会使匹配时间增多。

  • BAD
1
table > tbody > tr > th {…}
  • GOOD
1
.th-table {…}

避免使用通配符选择器

  • BAD
1
.selected * {color: red;}

浏览器会匹配文档中所有元素,然后分别向上逐级匹配class为selected的元素,
知道文档的根节点,因此匹配花销是非常大的,通常比开销最小的ID选择器高出1~3个数量级,所以应避免使用关键选择器是通配选择器的规则。

避免使用单规则的选择器

  • BAD
1
.selected [href=”#index”] {color: red;}

其匹配开销是非常大的,浏览器先匹配所有的元素,检查其是否有href属性并且herf属性值等于”#index”, 然后分别向上逐级匹配class为selected的元素,直到文档的根节点。所以应避免使用关键选择器是单规则属性选择器的规则。

避免使用类正则的选择器

CSS3添加了复杂的属性选择器,可以通过类正则表达式的方式对元素的属性值进行匹配。当然这些类型的选择器定是会影响性能的,正则表达式匹配会比基于类别的匹配会慢很多。大部分情况下我们应尽量避免使用 *=, |=, ^=, $=, 和 ~=语法的属性选择器。

适当调整你的选择器

  • BAD
1
#main-navigation li a { font-family: Georgia, Serif; }
  • GOOD (如果你需要的只是改变字体,这样写可能更有效)
1
#main-navigation { font-family: Georgia, Serif; }
  • BAD
1
#nav li a {…}
  • GOOD (如果要使用后代选择器,适当地缩小层级,降低CSS权重)
1
#nav a{…}

笔者认为…

笔者认为虽然ID是最高效的选择器,不过如果把所有要选择的元素全都写上ID也是一件很蠢的事…
ID选择器权重太高,不存在任何可重用性,因此要尽量少用ID选择器。
笔者倾向于使用类选择器,简短且语义化的命名,同时书写模块化的CSS会使你的CSS更容易扩展和可重用。


参考文献:
[1] CSS选择器的优化
[2] Writing efficient CSS
[3] Efficiently Rendering CSS
[4] 高性能CSS
[5] 你应该知道的一些事情——CSS权重

文章目录
  1. 1. 浏览如何识别选择器?
  2. 2. 如何写有效率的CSS选择器?
    1. 2.1. 选择器效率排序
    2. 2.2. 一些写高效CSS选择器的规则
      1. 2.2.1. 不要在ID选择器前加标签名或类
      2. 2.2.2. 不要在类前加标签名
      3. 2.2.3. 尽可能使用最具体的类别
      4. 2.2.4. 避免使用后代选择器
      5. 2.2.5. 标签分类规则不应该包含子元素选择器
      6. 2.2.6. 避免使用通配符选择器
      7. 2.2.7. 避免使用单规则的选择器
      8. 2.2.8. 避免使用类正则的选择器
      9. 2.2.9. 适当调整你的选择器
    3. 2.3. 笔者认为…