CSS进阶探讨-层叠特殊性及应用技巧

前言

本文共两个部分, 前面简要介绍CSS层叠特殊性的基本概念, 之后会探讨一些本人在项目中遇到的关于层叠的问题, 以及个人归纳的一些应用技巧.

关于层叠特殊性的详细文档可参考MDN (CSS层叠, Cascade and inheritance).

层叠特殊性基本概念

层叠

在样式表中, 同一个dom元素可能会有多条样式规则. CSS会通过一个层叠的处理过程, 为每一条规则分配一个重要度, 也就是特殊性, 并应用其中特殊性最高的规则.

特殊性

特殊性分类

选择器的特殊性分为四个等级,从高到低依次为:

  • A级: 行内样式
  • B级: id选择器总数
  • C级: 类,伪类,属性选择器总数
  • D级: 类型选择器,伪元素选择器总数
特殊性计算规则

层叠在计算特殊性高低时会首先从A级进行比较, 若相同则比较B级, 之后依次向下对比. 其中较大的规则, 其特殊性则越高.

需要特别说明的是, 若特殊性完全相等, 层叠会应用后定义的样式. 若使用CSS预编译工具, 编译后的结果中, 样式定义的顺序可能与预编译文档中顺序不一致, 这里需要特别注意.

计算示例

下表是特殊性计算的一些示例(示例中特殊性从高到低依次排列):

选择器特殊性(A,B,C,D)
style=””1,0,0,0
#wrapper #content {}0,2,0,0
#content .datePosted {}0,1,1,0
div #content {}0,1,0,1
#content {}0,1,0,0
p.comment .datePosted {}0,0,2,1
p.comment {}0,0,1,1
div p {}0,0,0,2
p {}0,0,0,1

</br>

层叠特殊性的应用技巧探讨

示例一: 区别一般样式与特殊样式,简化CSS

dom示例:

<div>
  <div class="page">
    <div class="news">
      <div class="post"><p>news content</p></div>
      <div class="post"><p>news content</p></div>
    </div>
    <div class="archive">
      <div class="post"><p>news content</p></div>
      <div class="post"><p>news content</p></div>
    </div>
  </div>
  <div class="page">
    <div class="news">
      <div class="post"><p>news content</p></div>
      <div class="post"><p>news content</p></div>
    </div>
    <div class="archive">
      <div class="post"><p>news content</p></div>
      <div class="post"><p>news content</p></div>
    </div>
  </div>
</div>

需求拟定:

  • 所有post字体大小为14px
  • 第一个page下,archive的第一个post为红色

样式表选择器可能是这样:

.post {
  color: gray;
  font-size: 14px;
}

.page:first-child .archive .post:first-child {
  color: red;
}

此处问题在于, 第二个选择器太长, 不便于阅读与理解, 维护的时候可能无法通过该选择器第一时间找到相关dom.

此时可以尝试添加一个特殊的样式类post-red以便于区分一般样式和特殊样式:

// 一般样式
.post {
  color: gray;
  font-size: 14px;
}

// 特殊样式
.post-red {
  color: red;
}

之后只需要在dom结构上添加对应class类名即可:

<div>
  <div class="page">
    <div class="news">
      <div class="post post-red"><p>news content</p></div>
      <div class="post"><p>news content</p></div>
    </div>
    <div class="archive">
      <div class="post"><p>news content</p></div>
      <div class="post"><p>news content</p></div>
    </div>
  </div>
  <div class="page">
    <div class="news">
      <div class="post"><p>news content</p></div>
      <div class="post"><p>news content</p></div>
    </div>
    <div class="archive">
      <div class="post"><p>news content</p></div>
      <div class="post"><p>news content</p></div>
    </div>
  </div>
</div>

这样处理的好处在于, 可以去掉之前样式表中复杂的多层选择器, 并且dom结构中, 能够明确表明哪一部分是经过了特殊处理, 更有利于后期维护.
</br>

示例二: 类名,ID名一般不使用与样式有关的名称,名称应体现其内容结构

依旧参照示例一中的dom结构与样式表, 而此时需求发生了更改, 需要将之前红色改为橘红色.

此时样式表可以由之前的

.post-red {
  color: red;
}

改为

.post-orange {
  color: orange;
}

而这里的问题在于class类名由post-red改为了post-orange, 意味着dom中被调用的位置也需要替换为新类名. 如果post-red被大量引用, 且这个关键词不止用于当前的类名, 可能需要我们手动筛选出项目中作为类名的post-red关键字, 并将其替换掉. 而项目中则应该避免这样耗时而重复的工作量.

上述示例中, 类名post-red更倾向于标明重点post, 但重点post不一定是红色, 所以使用post-point替代post-red可能更为合理.
</br>

示例三: 慎用层叠覆盖样式, 尤其慎用important覆盖样式

示例dom及样式表:

<div id="content">
  <div id="main-content">
    <h2>content 1</h2>
    <p>content 2</p>
    <div class="news-story">
      <h2 class="first">content 3</h2>
      <p>content 4</p>
    </div>
  </div>
</div>
#content div#main-content h2 {
  color: gray;
}
#content #main-content > h2 {
  color: blue;
}
body #content div[id="main-content"] h2 {
  color: green;
}
#main-content div.news-story h2 {
  color: orange;
}
#main-content [class="news-story"] {
  color: yellow;
}
#main-content div.news-story h2 .first {
  color: red;
}

此示例中, 应用于h2元素的选择器较多且较复杂, 所导致的问题是, 从样式表中去确认dom结构中具体h2的最终颜色将变得十分困难.

若此刻需求是需要content 1为红色, 可能会出现这样的样式解决问题:

#main-content div.news-story >h2 {
  color: red !important;
}

然而, 这样的处理方式, 会导致样式表更加复杂. 当需求不断变更, 越发复杂的样式表会导致其更加依赖这样简单覆盖的处理方式, 形成恶性循环. 当important已不再有效时, 最终的结果可能是整个样式推翻重写.

样式变更, 应该是优先考虑修改, 慎用覆盖.

总结

层叠特殊性方便了样式表的构建, 但同样易被滥用. 在实现需求时, 我们可能会选择简单粗暴的方案, 然而却会导致后期维护成本剧增. 参考一些简单技巧, 可以让项目更利于长期的扩展与维护.

    原文作者:黎杰_Lj
    原文地址: https://www.jianshu.com/p/afcb968f808c
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞