【重学前端】CSS选择器

236 阅读5分钟

选择器的优先级

各等级选择器

  • 0级

  • 通配符

  • 选择符:+ > ~ || 空格

  • 逻辑组合伪类::not() :is() :where()

  • 1级

  • 标签选择器

  • 2级

  • 类选择器

  • 属性选择器:.box[data-type="wuhu"]{color:#666}

  • 伪类:.box:hover

  • 3级

  • ID选择器

  • 4级

  • 内联属性

  • 5级

  • !important

选择器优先级的计算规则

业界流传甚广的数值计算法

body.foo:not([foo]){color:white}
// body 标签选择器  +1
// .foo 类选择器    +10
// :not 逻辑伪类    +1
// [foo] 属性选择器 +10
// 21

 不同等级之间的选择器是无法跨越优先级的,也就是说,11个类选择器也无法覆盖掉一个ID选择器的样式

CSS选择器最佳实践

命名建议全部小写

.box
.class-name
.header-nav

不要使用ID选择器

实在是想用的话,可以属性选择器替代,它的优先级和类选择器一样。如[id="someId"]{}

以为ID选择器的优先级实在是太高了。

不要使用嵌套选择器

如:

1.nav .li div {}
2.box .pic .icon {}
如今使用的sass less使得嵌套程度更深

缺点如下:

  • 渲染性能差
  • 优先级混乱
  • 样式布局脆弱

有两方面对渲染性能造成影响,1是标签选择器,2是过深的嵌套。

选择器性能

  • ID选择器
  • 类选择器
  • 标签选择器
  • 通配符
  • 属性选择器
  • 部分伪类::checked

其中ID选择器性能最好,与类选择器相差无几

.box>div{color:white}

这么看似乎不错的用法,其实很糟糕。

因为css选择器是从右往左进行匹配渲染的,也就是说会先匹配所有的div元素,再匹配.box类,如果页面都是div一把梭的话,会带来明显的渲染性能问题。

不过如果页面相对简单的话,其实可以不用太过于考虑这方面的问题,影响微乎其微。但复杂且元素多的话,就需要考虑了。

正确的选择器用法

使用无嵌套的纯类名选择器

<nav class="cs-nav">
    <li class="cs-nav-li"></li>
    <li class="cs-nav-li"></li>
</nav>

.cs-nav{}
.cs-nav-li{}

而不是像这种

<div class="box">
    <figure class="pic"><img src="./example.png” alt="示例图片">
        <figcaption><i class="icon"></i>图片标题</figcaption>
    </figure>
</div>
.box {}
.box .pic {}
.box .pic .icon {}

可以考虑使用tailwindcss和unocss

选择符

  • 后代选择符(空格)

  • 子选择符 >

  • 相邻兄弟选择符 +

  • 随后兄弟选择符 ~

  • 双管道选择符 ||

    后代选择符: ul li{color:white} 匹配ul下的所有li

    子选择符: ul > li{color:red} 匹配ul下的第一层li,深层嵌套不匹配

    相邻兄弟选择符: h1 + h2 {color:red} 同一层下匹配h1后面的第一个h2

    随后兄弟选择符 h1 ~ h2{color:pink} 同一层下匹配h1后面的所有h2

    双管道选择符 主要用于table

    后代选择符 子选择符 相邻兄弟选择符 随后兄弟选择符
    示例 .foo .bar {l .foo > .bar {) .foo + .bar {) .foo ~ .bar {y

    col.brother || td{color:red} .border占表格的两列,也就是匹配这两列的所有td

属性选择器

  • [attr="val"]

  • [attr~="val"]

  • [attr|="val"]

  • [attr^="val"]

  • [attr$="val"]

  • [attr*="val"]

    1
    2
    3
    4
    5
    [name="1 2"]{color:pink} 匹配name="1 2"的元素

    [name~="1"]{color:red} 匹配name的值里含有1的元素

    [name|="val"]{color:blue} 匹配name的值以val为开头的元素,它的值要么是val要么是val- 也就是说name="value"是不会被匹配到的

    以下三个可以加i来无视大小写 [name^="val" i] 匹配以val开头的所有元素 val val-1 value都会匹配到

    [name$="val" i] 匹配以val结尾的所有元素

    [name*="val" i] 匹配包含字符val的所有元素,像是JS正则test的用法

各种伪类

:hover

在鼠标移动到元素时触发,以下代码为鼠标移入元素时背景色变为pink

// html
<div></div>

// style
div{
    width:100px;
    height:100px;
    border:solid 1px black;
}
div:hover{
    background:pink
}

:active

当鼠标主键按下时,则触发active。如下代码,当主键按下时,div的背景色将会变为pink

// html
<div></div>

// style
...其它样式
div:active{
    background:pink
}

:focus

一般使用在可输入的元素下使用的伪类,如:input textarea,或是contenteditable设置为true的div元素。

// html
<input type="type"/>

// style
...其它样式
input:focus{
    background:pink
}

如果普通的div也想要有focus的话,可以设置一个属性tabindex="0"或者tabindex="-1"

0和-1的区别就是-1不能被tab触发,0可以。

:focus-within

和focus仅在当前元素聚焦时匹配不同,focus-within会在当前元素或其子元素聚焦时都会匹配

<div tabindex="0" class="box">
    <div tabindex="0" class="box-s"></div>
</div>


.box:focus-within{
    background:pink
}

:visited

用于a标签,匹配已访问过的链接

<a href="https://www.bilibili.com">BLBL</a>


a:visited{
    color:red
}

:target

可以匹配锚点,就是那个用于定位的锚点。例子如下:

// 这是一个链接:https://www.bilibili.com/#box

// html
<div id="box"></div>

// css
div:target{
    background:pink
}

上述代码被定位到的那个元素,会触发:target样式。

:enabled和:disabled

主要用于button和input元素,与元素属性enabled(启用)和disabled(禁用)并用。enabled可以不设置,因为默认就是启用状态

<button disabled></button>
<button></button>


// style
button:disabled{
    background:pink
}
button:enabled{
    background:red
}

:read-only和:read-write

只作用于input和textarea,默认就是read-write,可不做额外设置。

<textarea readonly></textarea>
<textarea></textarea>

// style
textarea:read-only{
    ...样式
}

textarea:read-write{
    ...样式
}

:placeholder-shown

当输入框的placeholder内容显示的时候,触发该伪类。可用于空值判断

<input type="text" placeholder="请输入"/>


// style
input:placeholder-shown{
    ...
}

:checked

匹配表单控件中设置了checked的元素。

<input type="radio" checked />

// style
input[type=radio]:checked{
    ...
}

:valid和:invalid

匹配验证通过(valid)或验证不通过(invalid)的表单。如下输入框,只允许输入3位英文字母。

<input type="text" pattern="[a-zA-Z]{3}" />


// style
// 输入通过
input:valid{
    color:green
}

// 输入不通过
input:invalid{
    color:red
}

:in-range和out-of-range

主要应用于<input type="number" /><input type="range" />控件,且需要设置min和max属性。顾名思义,:in-range伪类就是匹配输入的值在范围内的控件,:out-of-range反之。

:not()和:is()和:where()

<div></div>
<div wuhu></div>

// style
div:not([wuhu]){
    background:pink
}
div:is([wuhu]){
    background:red
}

很语义化的伪类,:not([wuhu])的意思就是,当div的属性没有wuhu这个属性时匹配样式。再比如:not(li),这一段指的就是当元素不为li时匹配样式。is反之。:where作用与:is相同,不同为:where优先级为0

:has()

是个很强大的伪类。但是兼容性不太好,FF不支持。Chrome和EDGE的版本得105往上,在safari中则很早开始支持了。

<div>
    <p></p>
</div>

// style
div:has(p){
    background:pink
}

上述代码指的是当div里有p标签时,则会将background设为pink

大致上就是这些,其他不经常用到的或者经常用到的就不做介绍了。可以自行去MDN查看