CSS的众多小技巧之选择器:你还在为样式不生效而感到苦恼吗?

精准命中

我写的样式老不生效啊,怎么办呢?要不来个important吧!反正催得急,先上线再说,有五个属性都要修改,但是都被覆盖了,emmm,那就加五个important吧。改到最后项目中随处都可见important的身影,当你或者其他人在为此抓狂的时候,它躲在一旁邪魅的一笑:就喜欢你看不惯我又干不掉我的样子!

简直笑哭

还有一种情况就是,不知道怎么选中需要设置样式的元素,所以就不断的加类名,费劲脑筋去想各种各样名称,又要见名知意,又要各有不同,因此五花八门越来越多的类名,搞得多人维护的项目变得越来越头大,甚至让人抓狂。

生无可恋

下面我们就来搞一搞,看看选择器有哪些好玩的地方。

优先级概念解析

一共大致分为五个等级:

  1. 内联样式:权重为(1,0,0,0)
  2. id选择器:权重为(0,1,0,0)。
  3. 类、伪类、属性选择器:权重为(0,0,1,0)。
  4. 标签、伪元素选择器:权重为(0,0,0,1)。
  5. 通用、子、相邻选择器:权重为(0,0,0,0)。

还有三个特殊的规则:!important、继承和默认代理样式。其中!important权重为无穷大。

他们之间的默认优先级顺序为:!important > 行内样式 > id选择器 > 类选择器 > 标签选择器 > 通用选择器 > 继承 > 代理(浏览器)默认属性。

样式生效的规则符合以下几点:

  1. 两个选择器权重不同时,权重搞得优先生效。
  2. 两个选择器权重相同时,后定义的优先生效(即层叠样式表的特性,后面定义的会覆盖前面定义的)。
  3. 被!important修饰的属性,会无条件的优先生效。

这里面还有几个需要注意的点:

  1. 所有权重中的0和1代表的是标识位,如内联样式的(1,0,0,0)代表第一等级标识位为1,并不是代表内联样式权重为1000,同样id选择器(0,1,0,0)代表第二个标识位为1,并不代表内联权重为100。也就是说#container {color: red}具有第二级权重。
  2. 同一权重等级下的选择器才可以累加,低等级权重的选择器永远不会超过高等级的选择器,如#a.b.c的优先级比#a.d的优先级要高,因为它们虽然都拥有第二等级权重,但是#a.b.c比#a.b多了一个第三等级的权重,而#a的优先级永远比.b.c(可以有任意多个低于第二等级权重的选择器)高,因为在进行权重比较的时候,是从高到低逐级比较的,#a选择器为第二等级,那么.b.c没有第二等级权重,即使有再多的第三级权重都没用。
  3. !important选择器虽然权重为无穷大,但是与数学中无穷大的比较不同,两个!important权重是可以进行比较的,两个同时拥有!important属性的选择器,也符合上面的比较规则,如#a中的!important要比.b中的!important优先级高。

权重逐级比较公式:(第一等级权重*该选择器个数,第二等级权重*该选择器个数,第三等级权重*该选择器个数,第四等级权重*该选择器个数,第五等级权重*该选择器个数)。

会逐个标识位进行比较,并不是进行简单的加法运算。

是的没错

写了这么长的文字,可是实在找不到可以插入一张图片的地方。总感觉思路会被打断。现在可以休息一下,稍后再往下看。

选择器类型解析

假设你已经对各种类型的选择器有所了解,知道了什么是类选择器、什么是内联样式、什么是标签选择器等。

接下来我们讨论一下几种组合选择器:(示例中都是用类名或标签作为选择器,因此为了简便,对于.a1这种的选择器,在表达的时候直接用a1来表示拥有类名a1的元素)

① *:这里先要介绍一下通用选择器,* {}选择器将会覆盖所有元素的代理默认样式,也可以用div.container * {}来指定对类名为container的div元素下的所有子孙元素应用样式。

② .a1 > .b1:表示给a1的子元素b1应用样式。只能是子元素,不包括孙子元素。

<style>
  .a1 > .b1{
    color: red;
  }
</style>
<ul class="a1">
  <li class="b1">1</li>
  <li>
      <span class="b1">2</span>
  </li>
</ul>

选择子元素

③ .b1 + .b2:表示给b1后面的紧跟着的b2应用样式。

<style>
  .b1 + .b2{
    color: red;
  }
</style>
<ul class="a1">
  <li class="b1">1</li>
  <li class="b2">2</li>
  <li class="b2">3</li>
</ul>

选择紧跟的

④ .b1 ~ .b2:表示给b1后面的b2应用样式。不用紧跟。

<style>
  .b1 ~ .b2{
    color: red;
  }
</style>
<ul class="a1">
  <li class="b1">1</li>
  <li class="b2">2</li>
  <li class="b2">3</li>
</ul>

选择后面的

⑤ li:first-child:表示给li应用样式,但是li必须是属于其父元素的第一个子元素。li:last-child与其类似,但是li必须是属于其父元素的最后一个子元素,不再给出示例。

<style>
  li:first-child{
    color: red;
  }
</style>
<ul>
  <li>1</li>
  <li>2</li>
  </ul>
  <ul>
    <li>3</li>
  <li>4</li>
</ul>

选择属于第一个子元素的

⑥ span:first-of-type:表示给span应用样式,其中只要span属于其父元素的所有子元素中的第一个span即可,即span前面的兄弟元素再没有其他的span,则应用样式。span:last-of-type与其类似,只是span后面的兄弟元素再没有其他的span,则应用样式,不再给出示例。

<style>
  span:first-of-type{
    color: red;
  }
</style>
<div>
  <span>1</span>
  <p>2</p>
  </div>
  <div>
    <p>3</p>
  <span>4</span>
</div>

选择第一种该类型

(Tips:first-child与first-of-type不同的地方在于,first-child必须是作为第一个子元素,而first-of-type是作为同一种类型中的第一个,他们都可修饰多个选择器,如.a.b:first-child。last-child和last-of-type同理。)

⑦ .b:not(li):表示给b应用样式,但是li除外。

<style>
  .b:not(li) {
    color: red;
  }
li:not(.a) {
  color: red;
}
</style>
<ul>
  <li class="a">1</li>
  <li class="b">2</li>
  </ul>
  <div>
    <div class="a">3</div>
  <div class="b">4</div>
</div>

"非"修饰符

⑧ li:nth-child(order):表示给li应用样式,但是li必须是属于其父元素的第order个子元素。li:nth-last-child(order)与其类似,但是li必须是属于其父元素的倒数第order个子元素,不再给出示例。

li:nth-child(2) {
  color: red;
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
</ul>

可以指定为第几个元素应用样式

这里还有一个小技巧,比如我想要选择前五个li,能做到吗?当然可以。请看代码。

<style>
  li:nth-child(-n + 5) {
    color: red;
  }
</style>
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
</ul>

选择前五个元素

这是因为除了可以指定order之外,还可以指定一个迭代序列n(从0开始),ul有8个li子元素,所以n可以取0,1,2,3,4,5,6,7,所以-n + 5可取出5,4,3,2,1,0,-1,-2,舍去负数,那么就是选中了1,2,3,4,5也就是前五个元素,注意这里只能写成-n + 5的形式,而不能写成5 - n的形式。

同样,它还有几种表达方式:(由于html部分与上面相同,不再重复列出)

<style>
  /* 选择第五个li元素,以及后面的所有li */
  li:nth-child(n + 5) {
    color: red;
  }
</style>

第五个及之后的元素

n+一个数字,表示这个数字以及之后的元素应用样式,-n+一个数字,表示这个数字以及之前的元素应用样式。

/* 以2的倍数选择li元素 */
li:nth-child(2n) {
  color: red;
}

只选择2的倍数

注意这里只能写成2n的形式,不能是2 * n或n * 2。

<style>
  /* 以2的倍数加1选择li元素 */
  /* n从0开始 */
  li:nth-child(2n + 1) {
    color: red;
  }
</style>

2的倍数加1

⑨ li:nth-of-type(order):只在li类型中查找符合条件的来应用样式,与nth-child一样,只不过加了个类型区分。li:nth-last-of-type(order)与其类似,但是li必须是属于其父元素的倒数第order个子元素,不再给出示例。

<style>
  /* 按照同类型查找,不会受div影响 */
  li:nth-of-type(2n) {
    color: red;
  }
</style>
<ul>
  <li>1</li>
  <li>2</li>
  <div>9</div>
  <div>10</div>
  <li>3</li>
  <div>11</div>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
</ul>

按照类型来查找

它们同样可以指定一个迭代序列n,与上面相同,故在此不做示例。

⑩ .a:only-of-type:表示给a应用样式,但是a的标签类型必须在其父元素中唯一。

<style>
  /* 注意:type指的是标签名要唯一才会生效 */
  .a:only-of-type {
    color: red;
  }
</style>
<div>
  <div class="a">1</div>
  <span>2</span>
  <p>3</p>
</div>
<div>
  <div class="a">1</div>
  <span>2</span>
  <p class="a">3</p>
  <!-- 如果去掉下面这一行,那么第一行的1也会变颜色 -->
  <div class="a">4</div>
</div>

对唯一的类型应用样式

哇!终于大概都讲完了。由于选择器太多了,篇幅有限,不能一一列举,其他的伪类、伪元素、属性选择器等,大家直接可以去官网查阅就可以了,都是基础的内容。

good job!

局部作用域

在vue中,由于组件化的概念,我们希望当前的样式只能当前文件中生效,不要影响全局的样式,因此可以给style标签设置scoped属性。这里有一套机制来保证每个组件间的样式是处于隔离状态的,不会互相影响,不但兄弟组件如此,父子组件也可以这样。

很好

这样是很好的,为我们带来了便利,并且不用为同名的问题所困扰,但是有一种情况是:当我们引用子组件的时候,想要修改它里面的样式,这个时候正常的选择器是无法生效的,我们无法选择到子组件里面的元素。

这是因为每一个组件都是独立样式作用域,它用一个唯一标识来区分,在父组件中写的样式,会自动在选择器的最后面加上这个唯一标识,而子组件中有自己的另一个唯一标识,所以会选择不到该元素。

这可怎么办?

这个时候我们可以使用一个叫做深度选择器的功能来帮助我们解决这个问题。

用>>>来表示,你也可以使用/deep/或者::v-deep,都代表相同的含义,只不过是写法不同,一个别名而已。

<style scoped lang="scss">
  .a >>> .b {
    color: red;
  }
</style>

经典案例

我们以下面这段html片段为例。

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
</ul>

区间选择: 我们可以指定一个区间来选择指定的元素。

<style>  
	/* 选择2到5之间的 */
  li:nth-child(n + 2):nth-child(-n + 5) {
    color: red;
  }
</style>

区间选择1

<style>
  /* 选择4以及之后的,但必须是2的倍数 */
  li:nth-child(n + 4):nth-child(2n) {
    color: red;
  }
</style>

区间选择2

<style>
  /* 选择3的倍数之外的 */
  li:not(:nth-child(3n)) {
    color: red;
  }
</style>

伪类选择: 我们可以通过伪类来做一些事情。

<style>
  span {
    cursor: pointer;
  }
  span + span {
    display: none;
  }
  span:hover + span {
    display: inline;
  }
</style>
<div>
  <span>查看识别码</span>
	<span>5201314</span>
</div>

默认状态

鼠标悬浮

题外话

说几句题外话,虽然不是选择器的内容,但是也跟它有关系,主要有以下几个方面:

  1. 我们在修改元素样式的时候,尽量先预设好选择器的样式,然后通过动态增加或移除相应的类名来达到效果,而不是直接设置style。
  2. 应该尽量避免使用id选择器,最好都通过标签、类名、属性选择器来操作样式。因为id选择器权重大,有时候覆盖起来不方便。而且id只能存在一个。再有一个就是id选择器会比类选择器给浏览器带来更大的负担。
  3. 尽量少使用!important,多通过上面讲述的权重规则来设定相应的样式。
  4. 尽量少用通用选择器,即通配符*,也会给浏览器增加负担。

CSS很厉害

总的来说

CSS选择器在我们实际开发工作当中不但是不可缺少的一部分,而且几乎时时刻刻都要与之打交道,熟练掌握他们的用法和原理,能够使我们在操作元素样式的时候得心应手,今天内容你学会了吗?[比心]

感谢阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值