助你再次理清CSS选择器

梳理选择器的种类,理解选择器的优先级,从而避免莫名其妙的样式重叠问题。

一、选择器的种类

1、基本选择器

  基本选择器包含:通配选择器、元素选择器、ID选择器、类选择器和群组选择器。

  对于类选择器的命名,'-'和'_'两者多有,具体可以看这里

  通配选择器(*),它用来选择所有元素,不过这个选择器的效率比较低,所以慎重选择,但是瞅了一眼Boostrap4.0是这样设置box-sizing:

    html {        box-sizing: border-box;
    }
    *, *::before, *::after {        box-sizing: inherit;
    }

  所以吧,也不是不能用,不过也就这一处,还是得少用。

  ID选择器,它的唯一性是规范,但是应用于多个元素,样式同样生效,不推荐这样做。

  群组选择器,通过逗号隔开,可以有效的减少一些冗余代码,例如上面的例子中:

    *, *::before, *::after {        box-sizing: inherit;
    }

2、属性选择器

  属性选择器主要针对于元素的属性值进行筛选,包含这几种操作符:=、|=、~=、*=、^=和$=:

  • [attr=val]:属性值为val;

  • [attr|=val]:属性值为val或者以val-开头;

  • [attr~=val]:属性值为val或者以多个空格分开含有val;

  • [attr*=val]:属性值包含val;

  • [attr^=val]:属性值以val开头;

  • [attr$=val]:属性值以val结尾。

  属性选择器的应用很多,例如Vue中的scoped css也正是利用属性选择器实现的。

3、层次选择器

  层次选择器包含后代选择器(E F)、子选择器(E > F)、相邻兄弟选择器(E + F)和通用选择器(E ~ F)。

  后代选择器与子选择器的区别:相比较前者,子选择器的搜索范围局限于儿子节点。

  相邻兄弟选择器,选择E后面相邻的兄弟节点F。很遗憾不能选择前面的。这个选择器的应用也很多,比如我们设置列表项之间的距离为20px:

    li:not(:last-child) + li {        margin-top: 20px;
    }

  通用选择器,选择E后面所有的兄弟节点F。同样上面的例子:

    li:first-child ~ li {        margin-top: 20px;
    }

  如果你能理解上面这两种写法,基本上这两个选择器你就理解了。

4、伪元素选择器

  首先对于伪元素的写法,标准是推荐双冒号,感觉这样写挺好的,可以和伪类区别开来。

  ::first-letter作用于整块文本的第一段的第一个文字,元素必须为块级元素。例如修饰段落第一个单词的样式:

    p::first-letter {        color: red;        font-size: 20px;
    }

  ::first-line则是作用于整块文本的第一段,同样必须为块级元素。

  ::before和::after分别向元素的前后添加内容,用处很大,比如我们实现这样的购物车:



641.jpg

                                                购物车



    <span role="btn" aria-label="购物车" attr-quantity="2" class="caricon"></span>
    /* 这里就不展现无关紧要的样式了 */
    .caricon {        /* 这里设置容器的样式 */
    }    .caricon::before {        /* 通过伪元素设置购物车图标 */
    }    .caricon::after {        /* 
            这两个伪元素多有一个重要的content属性,用来设置伪元素的内容 
            这里通过attr获取元素的属性值,实现购物车数量
        */
        content: attr(attr-quantity);
    }

  在一些网站中,当你鼠标选择文字会发生样式变化,这是因为用了::selection,不过它能改变的CSS属性比较有限,具体可以查询MDN。

  还有我们讨厌input的placeholder样式太丑时,你可以使用::placeholder来修改,但是这是一个试验性的伪元素,还有很多试验性的伪元素,有兴趣可以搜索一下。

5、伪类

  伪类的组成就更丰富了,这里选择两个比较重要可能还有点容易混淆的说说。

  首先看看否定伪类选择器:not,在前面的例子中你已经看到它的身影了,它匹配不符合描述的元素,用处可以说很大。

  然后就是结构伪类选择器,这里的内容也多,而且很容易混淆。

  例如:first-child和:first-of-type:

    p:first-child {        /* 计算范围:所有的兄弟节点 */
    }    p:first-of-type {        /* 计算范围:兄弟节点中所有p元素 */
    }

  同样还有:last-child和:last-of-type,就很容易懂了。

  :nth-child就比较强大了,不仅可以使用odd和even,还可以使用表达式。例如我们列表的斑马线:

    li:nth-child(even) {        background: red;
    }

  关于:nth-child重要的几点可以总结为:

  • 值的下标是从1开始的;

  • 但是n的下标是从0开始;

  • 当表达式的值为0或者负数是无效的;

  • 采用表达式可以实现很多需求,例如我只想让列表的前三项设置样式:nth-child(-n + 3);

  像什么:nth-of-type,:nth-last-child和:nth-last-of-type是不是小case了。

  :only-child表示父节点只有一个子节点,其实学习了上面的一些选择器,我们完全可以找到等价的表达方式:

    li:first-child:last-child {        background: yellow;
    }

  当然还有:only-of-type是必不可少的。

二、选择器的优先级

  上面这么多的选择器,是不是很头大,这也是为什么这里要特地说一下选择器优先级。当多条样式应用在一个元素上,系统会将样式合并,当一个属性被赋了多次值,到底取哪个值呢?这时候就需要优先级了,优先级高的覆盖优先级低的。

  选择器优先级规则:

  • 首先通配符是没有权重的(所以我感觉这点也是不推荐使用它的原因);

  • !important的权重bug级的高;

  • 权重第二高的就是元素的行内样式(style属性中的值);

  接下来的情况我们可以数值化:

  • id选择器的权重为100;

  • 类选择器、属性选择器和伪类选择器的权重为10;

  • 元素和伪元素的权重为1。

  • 如果优先级一样,则后声明的优先级高。

  看个例子:

    li {        width: 300px;        height: 90px;        background: red;
    }    ul li {        background: yellow;
    }

  首先对于没有重复赋值的width和height,并不存在什么优先级的问题,而对于background,第一个样式的优先级为1,而第二个样式的优先级为2,所以将yellow赋值给background。

三、总结

  前面写了很多废话,也没有将选择器罗列完整,但是基本的构成,大家应该很清晰了。

  对于后面说的选择器优先级的计算,并不是说你每次写完样式多要求算一下,最重要的目的是:你理解计算规则后,让你对每种选择器的应用场景更加清晰,而不是说随便用,从而造成意想不到的样式覆盖问题。


上一篇: 没有上一篇了 下一篇: 编写优秀 CSS 代码的 8 个策略
2613 2017-09-16

JavaScript >>

Linux >>

PHP >>

HTML/CSS >>

C/C++ >>

MySql >>

常用工具使用 >>