• 深入理解CSS选择器优先级


    题外话

    今天把 《CSS REFACTORING》(中文名叫《CSS重构:样式表性能调优》)电子书粗略的浏览了一遍,这本书很薄,150页左右,首先是介绍了什么是重构并举了两个简单的重构例子,然后介绍了CSS的选择器优先级,再然后介绍了CSS的最佳实践, 再然后就介绍如何重置浏览器的默认样式,最后比较虚的、纯理论的介绍了CSS重构的策略,然后就没有然后了。这书整体内容很简单,但是,其中对于 CSS选择器优先级计算 作了比较深入的讲解。

    什么是选择器优先级(Specificity)

    直接复制了 MDN对优先级的定义 上的解释:

    浏览器通过优先级来判断哪一些属性值与一个元素最为相关,从而在该元素上应用这些属性值。优先级是基于不同种类选择器组成的匹配规则。

    这句话也是很抽象,暂且先不管它了。但是我们可以先看一个例子:

    • HTML:
    <div id="content" class="content">
    我是什么颜色
    </div>
    
    • CSS:
    #content {
        color: #f00;
    }
    .content {
         color: #0f0;
    }
    

    那最后文字是什么颜色呢?答案很简单:红色。这就涉及到了优先级问题,同一块内容,我们同时用了 ID选择器类选择器,因为 ID选择器 优先级大于 类选择器 , 所以最终显示为红色。

    优先级的计算规则

    相信每位写过CSS的朋友都知道,CSS选择器的优先级关系是:

    内联 > ID选择器 > 类选择器 > 标签选择器。

    但是,浏览器具体的优先级算法是怎样的?可能还有些人不知道 。《CSS REFACTORING》 中提到了算法的过程 。

    A specificity is determined by plugging numbers into (a, b, c, d):

    1. If the styles are applied via the style attribute, a=1; otherwise, a=0.
    2. b is equal to the number of ID selectors present.
    3. c is equal to the number of class selectors, attribute selectors, and pseudoclasses present.
    4. d is equal to the number of type selectors and pseudoelements present.

    翻译过来就是

    优先级是由 ABCD 的值来决定的,其中它们的值计算规则如下:

    1. 如果存在内联样式,那么 A = 1, 否则 A = 0;
    2. B 的值等于 ID选择器 出现的次数;
    3. C 的值等于 类选择器属性选择器伪类 出现的总次数;
    4. D 的值等于 标签选择器伪元素 出现的总次数 。

    这样子直接看好像也还是很明白 ,那先上个例子:

    #nav-global > ul > li > a.nav-link
    

    套用上面的算法,依次求出 A B C D 的值:

    1. 因为没有内联样式 ,所以 A = 0;
    2. ID选择器总共出现了1次, B = 1;
    3. 类选择器出现了1次, 属性选择器出现了0次,伪类选择器出现0次,所以 C = (1 + 0 + 0) = 1
    4. 标签选择器出现了3次, 伪元素出现了0次,所以 D = (3 + 0) = 3;

    上面算出的ABCD 可以简记作:(0, 1, 1, 3)

    为了熟悉掌握优先级算法 ,我们再来做一些练习:

    li                                  /* (0, 0, 0, 1) */
    ul li                               /* (0, 0, 0, 2) */
    ul ol+li                            /* (0, 0, 0, 3) */
    ul ol+li                            /* (0, 0, 0, 3) */
    h1 + *[REL=up]                      /* (0, 0, 1, 1) */
    ul ol li.red                        /* (0, 0, 1, 3) */
    li.red.level                        /* (0, 0, 2, 1) */
    a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11  /* (0, 0, 11,0) */
    #x34y                               /* (0, 1, 0, 0) */
    li:first-child h2 .title            /* (0, 0, 2, 2) */
    #nav .selected > a:hover            /* (0, 1, 2, 1) */
    html body #nav .selected > a:hover  /* (0, 1, 2, 3) */
    

    OK, 现在已经弄清楚了优先级是怎么算的了。但是,还有一个问题,怎么比较两个优先级的高低呢?
    比较规则是: 从左往右依次进行比较 ,较大者胜出,如果相等,则继续往右移动一位进行比较 。如果4位全部相等,则后面的会覆盖前面的

    再来看一下例子:

    • html:
    <div class="nav-list" id="nav-list">
    	<div class="item">nav1</div>
    	<div class="item">nav2</div>
    </div>
    
    • CSS:
    #nav-list .item {
    	color: #f00;
    }
    
    .nav-list .item {
    	color: #0f0;
    }
    

    算出 #nav-list .item 的优先级是 (0, 1, 1, 0), .nav-list .item 的优先级是 (0, 0, 2, 0)。 左边第一位都是0, 再看看左边第二位,前者是1,后者是0, 所以(0, 1, 1, 0) 的大于 (0, 0, 2, 0) ,即 #nva-list .item 大于 .nav-list .item,所以字体会是红色。

    优先级的特殊情况

    经过上面的优先级计算规则,我们可以知道内联样式的优先级是最高的,但是外部样式有没有什么办法覆盖内联样式呢?有的,那就要 !important 出马了。因为一般情况下,很少会使用内联样式 ,所以 !important 也很少会用到!如果不是为了要覆盖内联样式,建议尽量不要使用 !important 。、

    那可能有人会想,那如果我内联样式用了 !important,是不是外部样式就没有办法了呢?比如下面的代码:

    • HTML:
    <div class="app" style="color:#f00!important">666</div>
    
    • CSS:
    .app {
    	color: 0f0!important;
    }
    

    是的,你赢了,这时候内联样式已经强大到不管你外部样式怎么写都无法覆盖它了。这种情况在实际代码中是要杜绝的!记住,千万不要在内联样式中使用 !important

    最后 , !important 真的是的无法超越的王者吗?其实不是的,一些情况,我们可以超越 !important, 请看下面的例子:

    • html:
    <div class="box" style="background: #f00;  300px!important;"><div>
    
    • css:
    .box {
    	max- 100px;
    }
    

    这时候 .box 的宽度只有 100px , 而不是 300px, 可见,max-width 可以超越 width!important!但是,这实际上不是优先级的问题,因为优先级是比较相同属性的,而 max-widthwidth 是两个不同的问题。之所以举这个例子,是要告诉大家,有时候不管怎么设置容器的 width 都不生效,检查一下是不是有人写了 max-width 坑了你哈。

    OK,优先级先写到这里啦,朋友们有问题欢迎留言讨论~

  • 相关阅读:
    怎样快速缩小问题的排查范围
    Android Activity启动模式图解
    只有理解了部分是怎么组合到整体上的,才能理解元素的真正功能
    aop收口要寻找最窄的切面
    错误的本质是不一致
    代理:接口一致、创建混入(替代)、消息转发
    分解与组合是终极方法论(还原论)
    OC之NSURLsession
    一个高频问题:异步操作会创建线程吗?
    关于Chrome跨域The request client is not a secure xxx相关提示的解决
  • 原文地址:https://www.cnblogs.com/yugege/p/9918232.html
Copyright © 2020-2023  润新知