CSS 知识体系之 CSS 选择器

5f17d69966a2e585

这是我参与更文挑战的第五天,活动详情查看:更文挑战

层叠样式表 (Cascading Style Sheets,缩写为CSS),是一种 样式表 语言,用来描述HTMLXML(包括如SVGMathMLXHTML之类的XML分支语言)文档的呈现。CSS` 描述了在屏幕、纸质、音频等其它媒体上的元素应该如何被渲染的问题。

CSS 选择器规定了 CSS 规则会被应用到哪些元素上。

1.1 简单/基本选择器

标签/元素选择器:

  • 按照给定的节点名称,选择所有匹配的元素。

  • 语法:elementname

  • 例子:input 匹配任何 <input> 元素。div(标签选择器) svg|a(命名空间选择器-html 部分的知识)

类选择器:

  • 按照给定的 class 属性的值,选择所有匹配的元素。

  • 语法:.classname,.class (支持用空格分隔多个)

  • 例子:.index 匹配任何 class 属性中含有 “index” 类的元素。

ID 选择器:

  • 按照 id 属性选择一个与之匹配的元素。需要注意的是,一个文档中,每个 ID 属性都应当是唯一的。

  • 语法:#idname,#id(必须完全匹配)

  • 例子:#toc 匹配 ID 为 “toc” 的元素。

属性选择器:

  • 按照给定的属性,选择所有匹配的元素。

  • 语法:[attr] [attr=value] [attr~=value] [attr|=value]``[attr^=value] [attr$=value] [attr*=value]

  • 例子:[autoplay] 选择所有具有 autoplay 属性的元素(不论这个属性的值是什么)。

/* 匹配存在title属性的a标签*/
a[title] {
  color: purple;
}

/* 匹配href="https://example.org"的a标签 */
a[href="https://example.org"]
{
  color: green;
}

/* 匹配href的内容包含"example"的 a 标签 */
a[href*="example"] {
  font-size: 2em;
}

/* 匹配href的内容以 ".org" 结尾的a标签 */
a[href$=".org"] {
  font-style: italic;
}

/* 匹配class属性的内容包含"logo"的 a标签 */
a[class~="logo"] {
  padding: 2px;
}

伪类选择器:

  • : 伪选择器支持按照未被包含在文档树中的状态信息来选择元素。

  • 例子:a:visited 匹配所有曾被访问过的 <a> 元素。:hover (伪类)

伪元素选择器:

  • :: 伪选择器用于表示无法用 HTML 语义表达的实体。

  • 例子:p::first-line 匹配所有 <p> 元素的第一行。::before (伪元素)

1.2 选择器语法

1.2.1 复合选择器

复合选择器即多个简单选择器的组合,此情况下必须匹配每一个选择器

  • <简单选择器><简单选择器><简单选择器>
  • * 或者 div 必须写在最前面, 伪类伪元素写在最后面

1.2.2 选择器列表

  • , 是将不同的选择器组合在一起的方法,它选择所有能被列表中的任意一个选择器选中的节点。

  • 语法:A, B

  • 示例:div , span 会同时匹配 <span> 元素和 <div> 元素。

/*

*/
div,
#id,
.class {
}

1.2.3 复杂选择器

复杂选择器也叫组合器, 是把复合选择器用一定的操作符链接

  • <复合选择器><sp><复合选择器>
  • <复合选择器>><复合选择器>
  • <复合选择器>~<复合选择器>
  • <复合选择器>+<复合选择器>
  • <复合选择器>||<复合选择器>
1.2.3.1 子孙选择器

子孙选择器也叫后代组合器(Descendant combinator)

  • (空格)组合器选择前一个元素的后代节点。

  • 语法:A B

  • 例子:div span 匹配所有位于任意 <div> 元素之内的 <span> 元素。

/*

选中 div 下面 含有  .class 的所有子元素
*/
div .class {
}
1.2.3.2 子选择器

子选择器也叫直接子代组合器(Child combinator)

  • > 组合器选择前一个元素的直接子代的节点。

  • 语法:A > B

  • 例子:ul > li 匹配直接嵌套在 <ul> 元素内的所有 <li> 元素。

  • 特点: 只能选择子一级,是一个严格的父子关系

/*
选中 div 下面 含有  .class 的一个子元素
*/
div > .class {
}
1.2.3.3 兄弟选择器

兄弟选择器也叫一般兄弟组合器(General sibling combinator)

  • ~ 组合器选择兄弟元素,也就是说,后一个节点在前一个节点后面的任意位置,并且共享同一个父节点。

  • 语法:A ~ B

  • 例子:p ~ span 匹配同一父元素下,<p> 元素后的所有 <span> 元素。

/*

*/
div ~ .class {
}
1.2.3.4 邻居选择器

邻居选择器也叫紧邻兄弟组合器(Adjacent sibling combinator)

  • + 组合器选择相邻元素,即后一个元素紧跟在前一个之后,并且共享同一个父节点。

  • 语法:A + B

  • 例子:h2 + p 会匹配所有紧邻在 <h2> (en-US) 元素后的 <p> 元素。

/*

*/
div + .class {
}
1.2.3.5 双竖线(level4 标准)
  • || 组合器选择属于某个表格行的节点。

  • 语法: A || B

  • 例子: col || td 会匹配所有 <col> 作用域内的 <td> 元素。

table 里面去选中一列

/*

*/
div||.class {
}

2. 选择器优先级

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ptS6GCV9-1623058959178)(https://qiniu.nsuedu.cn/react-lib/20210607152853.png)]

从高到低排列有

  1. 行内样式

给元素添加的内联样式 (例如,style="font-weight:bold") 总会覆盖外部样式表的任何样式 ,因此可看作是具有最高的优先级。

  1. 关系选择符(combinators)

    • +

    • >

    • ~

    • (空格)

    • ||否定伪类(negation pseudo-class)(:not())对优先级没有影响。(但是,在:not() 内部声明的选择器会影响优先级)。

  2. 通配选择符(universal selector,即*

  3. ID 选择器(例如,#example)。

  4. 类选择器 (例如,.example),属性选择器(例如,[type="radio"])和伪类(例如,:hover

  5. 类型选择器(例如,h1)和伪元素(例如,::before

可以访问以下来了解更多关于优先级的详细信息。

2.1 简单选择器优先级的如何计算

当我们用一个非常复杂的规则去选择元素时,最终优先级可以用一个"四元组"来表示:

[inline(最高),id 个数,class 个数,tag 个数]

结果从后往前数(因为最后一位是 inline,优先级最高)

CSS 标准中我们需要使用一个足够大的 N 进制 来进行计算出优先级


在简单选择器中, 除了 #id, .class, 其他简单选择器的优先级是一样的

/*1             2*/
#id div.a#id {
  /**/
}

/* [0,2,1,1] */

S = 0 _ N+ 2 _ N + 1 N+1

取 N = 1000000

S = 2000001000001


请使用[inline(最高),id 个数,class 个数,tag 个数]的范式写出下面选择器的优先级:

  • div#a.b .c[id=x]
  • #a:not(#b)
  • .a
  • div.a

正确答案

  • [0,1,3,1]
  • [0,2,0,0]
  • [0,0,1,0]
  • [0,0,1,1]

解析 div#a.b .c[id=x]的优先级

相同的规则的优先级–二者相等()

优先级相同,后面的规则会覆盖前面的规则

<style>
  div#a.b .c[id="x"] {
    color: red;
  }

  /*
	优先级相同,后面的规则会覆盖前面的规则
	*/
  div#a.b .c[id="x"] {
    color: blue;
  }
</style>

<div id="a" class="b">
  <div class="c" id="x">666</div>
</div>

id 选择器优先级 > 属性选择器优先级

<style>
  /*
    #x 与  [id=x] 相比,  #x优先级跟高
  */
  div#a.b .c#x {
    color: red;
  }

  div#a.b .c[id="x"] {
    color: blue;
  }
</style>

<div id="a" class="b">
  <div class="c" id="x">666</div>
</div>

class 选择器优先级 === 属性选择器优先级

<style>
  /*
    .d 与  [id=x] 相比,  二者优先级是一致的
  */

  div#a.b .c.d {
    color: red;
  }

  div#a.b .c[id="x"] {
    color: blue;
  }
</style>

<div id="a" class="b">
  <div class="c d" id="x">666</div>
</div>
<style>
  /*
    .d 与  [id=x] 相比,  二者优先级是一致的
  */

  div#a.b .c.d {
    color: blue;
  }

  div#a.b .c[id="x"] {
    color: red;
  }
</style>

<div id="a" class="b">
  <div class="c d" id="x">666</div>
</div>

解析 #a:not(#b)的优先级

伪类是不参与优先级计算的

<style>
  /*
       伪类是不参与优先级计算的
       但是,在 :not() 内部声明的选择器会影响优先级

      MDN中说到(https://developer.mozilla.org/zh-CN/docs/Web/CSS/:not)
      可以利用这个伪类提高规则的优先级。例如, #foo:not(#bar) 和 #foo 会匹配相同的元素,
      但是前者的优先级更高。
    */
  #a:not(#b) {
    color: green;
  }

  #a {
    color: black;
  }
</style>

<div id="x" class="b">
  <div class="c d" id="a">666</div>
</div>
<style>
  /*
       伪类是不参与优先级计算的

    */
  #a:not(#b) {
    color: green;
  }

  #x #a {
    color: black;
  }
</style>

<div id="x" class="b">
  <div class="c d" id="a">666</div>
</div>

解析 .a 与 div.a 的优先级

* 号不会影响优先级

<style>
  /*
       * 号不会影响优先级

    */
  div.a {
    color: brown;
  }

  *.a {
    color: green;
  }
</style>

<div id="x" class="b">
  <div class="a" id="a">666</div>
</div>
  1. 复杂选择器的优先级就是把每个简单选择器的优先级加起来吗? 是的!
  2. transform 不会改变别的元素, 只会改变自身元素位置,会改变重绘,
  3. css 有继承吗? 是指子元素属性与父元素属性的继承, 不是 面向对象说到的继承

3 . 伪类

表示链接/行为的伪类

CSS 伪类 选择器代表一个有链接锚点的元素,而不管它是否被访问过,也就是说,它会匹配每一个有 href 属性的 <a><area><link> 元素。因此,它会匹配到所有的 :link:visited

any-link

active 表示当所指元素处于激活状态(鼠标在元素上按下还没有松开)时所显示的颜色。

focus 表示元素获得光标焦点时使用的颜色,主要用于文本框输入文字时使用(鼠标松开时显示的颜色)。

伪类的顺序应为:

  1. :link
  2. :visited
  3. :hover
  4. :focus
  5. :active
a:link {
  color: blue;
} /* 未访问链接 */
a:visited {
  color: purple;
} /* 已访问链接 */
a:hover {
  background: yellow;
} /* 用户鼠标悬停 */
a:active {
  color: red;
} /* 激活链接 */

p:active {
  background: #eee;
} /* 激活段落 */

表示树形结构的伪类

代表没有子元素的元素。子元素只可以是元素节点或文本(包括空格)。注释或处理指令都不会产生影响。

在玩具浏览器中,在 startTag 的时候去做 computeCSS,

至少要到 endtag 之后的下一个 token 是什么

至少要到标签结束的时候,再往后扫一个 token,才能知道是不是 此伪类对应的元素

是无法实现的,在真实代码场景中不建议使用,

CSS 回溯问题

逻辑型

not 中加复杂选择器, 可以这样使用

4.伪元素

<div>
  <::before/> content content content content content content content content
  content content content content content content content content <::after/>
</div>
<div >
<::first-letter/>c</::first-letter> ontent content content content
    content content content content
    content content content content
    content content content content
</div>
<div>
<::first-line/>content content content content </::first-line>
    content content content content
    content content content content
    content content content content
</div>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ym9yrVuc-1623058959179)(https://cdn.nlark.com/yuque/0/2020/svg/382504/1591027251680-b487287c-57b4-401b-a904-2569f1ca9333.svg)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Krykf6W-1623058959180)(https://cdn.nlark.com/yuque/0/2020/svg/382504/1591027251677-6db1cf0f-b113-4ae2-9d80-d49e16b33292.svg)]

思考:

  • 编写一个 match 函数
function match(selector, element) {
  return true;
}
// 第一个参数:任意选择器
// 第二个参数,定位html中一个已存在的元素
// 结果: 返回第一个参数与第二个参数是否相等
match("div #id.class", document.getElementById("id"));

<body>
  <div>
    <div id="id" class="class">1</div>
    <div class="class">2</div>
  </div>
</body>
<script>
  function match(selector, element) {
    // 返回与指定的选择器组匹配的文档中的元素列表 (使用深度优先的先序遍历文档的节点)。返回的对象是 NodeList 。
    const nodeList = document.querySelectorAll(selector);
    for (let e in nodeList) {
      // 给定的元素与 NodeList的某一项是否匹配
      return nodeList[e] === element;
    }
    return false;
  }

  const mydiv = document.getElementById("id");

  const res = matchesSelector("div #id.class", mydiv);

  console.log(res);
</script>

最后

文章浅陋,欢迎各位看官评论区留下的你的见解!

觉得有收获的同学欢迎点赞,关注一波!

20210531095857

往期文章

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值