CSS选择器是用来指定网页上我们想要样式化的HTML元素。CSS中提供了很多种类的选择器,本文将简单介绍CSS中目前存在的所有类型的选择器。
HTML中应用CSS的三种方式
由于本文涉及到样式的优先级,所以在介绍css选择器之前,简单了解一下在HTML中应用CSS的三种方式。
1. 内联样式表
内联样式表 指的是将CSS样式放在 HTML 元素的 style 属性之中,只能修饰某一个HTML元素的样式。
例如:给 h1
标签设置字体颜色为红色,黑色变框,内联样式表如下所示。
<h1 style="color: red; border: 1px solid black;">Hello World!</h1>
内联样式表的优缺点如下:
- 优点:
- 书写简单,直观清晰
- 无需引入外部样式文件,某些情况下提升了效率
- 缺点:
- 代码冗余,难以维护。例如给同一类型标签设置相同样式时,需要给每个标签的
style
属性都加上相关样式。当更新样式时,需要逐个修改,操作繁琐 - 文档结构和样式混合在一起,会导致代码结构混乱,难以阅读和理解。
- 代码冗余,难以维护。例如给同一类型标签设置相同样式时,需要给每个标签的
但在实际开发过程中,一般很少使用内联样式表
2. 内部样式表
内部样式表 指的是将CSS样式放在文档<head>
标签中的<style>
标签之中。
如下代码所示,可通过在<style>
标签中设置HTML元素的样式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
h1 {
color: red;
border: 1px solid black;
}
</style>
</head>
<body>
<h1>Hello World!</h1>
<h1>Hello Everybody!</h1>
</body>
</html>
- 相对于内联样式表而言,这种方式一定程度上解决了代码冗余、结构混乱等问题,使得HTML元素之间能够共享样式。
- 相对于外部样式表而言,内部样式表的
- 优点在于减少了一次HTTP请求。
- 缺点在于同一站点里的每个页面都需要重复添加相同的CSS,页面之间无法共享样式。而且样式和结构仍在同一个html文件中,导致页面不纯净。
3. 外部样式表
外部样式表 是指将CSS编写在扩展名为.css
的单独文件中,并从HTML中的<link>
元素引用它。
HTML文件:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<h1>Hello World!</h1>
<h1>Hello Everybody!</h1>
</body>
</html>
CSS文件:style.css
h1 {
color: red;
border: 1px solid black;
}
相对于内联样式表和内部样式表而言,外部样式表有如下优缺点:
- 优点
- 实现了结构和样式的分离,代码结构清晰,易于阅读和理解
- 代码易于维护和复用
- 对搜索引擎友好
- 外部样式存放在独立的文件中,可缓存在客户端,无需多次加载
- 缺点
- 每引入一个CSS文件都会进行一次HTTP请求,如果样式文件过多,会造成服务器压力
- 此外,样式文件过多会阻塞dom树的渲染
当对某一HTML元素同时设置了内联样式表、内部样式表、外部样式表时,哪种方式的优先级更高呢?
如下例子中,<h1>
元素的表现的颜色为红色(red),这说明内联样式表优先级最高。
index.css
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./style.css">
<style>
h1 {
color: yellow;
}
</style>
</head>
<body>
<h1 style="color: red" >Hello World!</h1>
</body>
</html>
style.css
h1 {
color: blue;
}
当我们删除<h1>
标签中的内联样式后,<h1>
元素的表现的颜色为黄色(yellow),但这并不表明内部样式表的优先级高于外部样式表,当我们将代码改成如下形式后,<h1>
元素的表现的颜色为蓝色(blue)。
<style>
h1 {
color: yellow;
}
</style>
<link rel="stylesheet" href="./style.css">
这说明最终表现得样式和书写得位置有关,后声明样式会覆盖先声明的样式,即就近原则。但是这种说法不是绝对的,仅针对相同选择器,且样式表中不存在!important
时才会成立。
总结来说:内联样式表 > 内部样式表 = 外部样式表 (内部样式表、外部样式表的优先级与书写位置相关,后声明的会覆盖先声明的)
上面我们简单介绍了如何在HTML文档中应用CSS样式。内联样式表直接放在标签的style
属性中,而对于内部样式表和外部样式表,首先需要确定我们想要样式化的HTML元素,对此CSS选择器提供了很多种方法,接下来就了解一下CSS选择器。
一、基础选择器
1.1 类型选择器(Type Selector)
类型选择器(元素选择器、标签选择器):指用HTML标签名称作为选择器,按标签名称分类,为页面中某一类标签指定统一的css样。基本语法如下所示:
标签名 {
属性1: 属性值1;
属性2: 属性值2;
……
}
类型选择器允许可选的命名空间组件:可将事先声明的命名空间前缀添加到元素名称之前,通过命名空间分隔符(|
)分隔。
ns|E
:选择命名空间 ns 中名称为 E 的元素*|E
:选择任何命名空间中名称为 E 的元素,包括没有命名空间的元素|E
:选择没有命名空间的名称为 E 的元素E
:如果指定了默认命名空间,则等同于ns|E
其中 ns 代表默认命名空间,如果未指定 默认命名空间,则等同于*|E
如下示例:
@namespace foo url(http://www.example.com);
/* 匹配命名空间 http://www.example.com 中的所有 h1 元素 */
foo|h1 { color: blue } /* first rule */
/* 匹配命名空间 http://www.example.com 中的所有元素 */
foo|* { color: yellow } /* second rule */
/* 匹配没有命名空间的 h1 元素 */
|h1 { color: red } /* ...*/
/* 匹配任何命名空间中的 h1 元素(也包括没有命名空间的 h1 元素) */
*|h1 { color: green }
/* 由于未指定默认命名空间,所以等同于 *|E */
h1 { color: green }
1.2 全局选择器 (Universal Selector)
全局选择器(通配符选择器),是由一个星号(*
)代指的,它选中了文档中的所有内容(或者是父元素中的所有内容,比如,它紧随在其他元素以及邻代运算符之后的时候)。基本语法如下:
* {
属性1: 属性值1;
属性2: 属性值2;
……
}
全局选择器通常会被用于做一些初始化操作,例如设置全局内外边距为0:
* {
margin: 0;
padding: 0
}
当全局选择器(*
)并非简单选择器序列中的唯一组成部分时,那么 *
可以被省略。如下示例:
*[hreflang|=en] 等价于 [hreflang|=en]
*.warning 等价于 .warning
#myid 等价于 #myid
但有些情况下,并不建议省略*
,例如:我想选中任何<article>
元素的第一子元素,不论第一个元素的类型是什么,我们可以通过伪类选择器实现article :first-child
,但是这会和article:first-child
混淆,而后者选择了作为其他元素的第一子元素的<article>
元素。
为了避免这种混淆,我们可以向:first-child
选择器加入全局选择器,这样选择器所做的事情很容易就能看懂。选择器正选中<article>
元素的任何第一子元素:article *:first-child
这种方式使得选择器更加具有可读性。
当然,全局选择器也可以指定命名空间,规则与类型选择器相同。但如果命名空间前缀未声明,那么该全局选择器无效。
1.3 类选择器(Class Selector)
类选择器以一个句点(.
)开头,会选择文档中应用了这个类的所有元素。换个角度来看,类选择器其实就是属性选择器[class="value"]
的替代方法。基本语法如下所示:
.类名 {
属性1: 属性值1;
属性2: 属性值2;
……
}
- 类选择器使用英文符号 "." 进行标识,后面紧跟类名
- 类名较长或者是词组时,可以使用横线 "-"
- 类名不要使用纯数字、中文命名,尽量使用英文字母来表示
如下代码,当我们想给标题和第二段文本设置高亮时,可给对应标签设置同一类名highlight
。
<body>
<h1 class="highlight">标题</h1>
<p>段落1</p>
<p class="highlight">段落2</p>
</body>
然后使用类选择器同一设置样式:
.highlight {
background: red;
}
(1)指向特定元素的类
对于上述例子,有两个类名为highlight
的标签,但是我们只想高亮h1
标签,此时我们可以建立一个指向应用一个类的特定元素。基本语法如下,标签和类名之间没有空格:
标签.类名 {
属性1: 属性值1;
属性2: 属性值2;
……
}
即:
h1.highlight {
background: red;
}
当然,我们想给多个同类型标签中某个具有特定类名的标签设置样式也可以使用这种选择器。
(2)多类名
一个标签可以指定多个类名,各个类名之间可以用空格隔开。这种方式可以把一些标签元素相同的样式放到同一个类。这些标签都可以调用这个公共的类,然后再调用自己独有的类。能够节省css代码,统一修改也非常方便
<div class="name1 name2 name3"><div/>
例如下面代码中有三个消息盒子,我们想统一设置字体大小为14px
,然后不同类型设置不同颜色:
<div class="message info">信息</div>
<div class="message warning">警告</div>
<div class="message error">错误</div>
css代码中可以写成如下形式:
.message {
font-size: 14px;
}
.warning {
color: orange;
}
.error {
color: red;
}
通过message
类统一设置字体大小,然后通过每个标签独有的类名设置字体颜色,表现如下:
为了告诉浏览器我们只想匹配带有所有这些类的元素,我们可以将这些类不加空格地连成一串。
例如,我们想要选择类名中包含message
和info
的标签:
.message.info {
font-size: 20px;
font-weight: 500;
}
多类名的优先级
当某个标签拥有多个类名时,选择器的优先级与标签中类名的先后顺序无关,而是由以下两个因素决定的:
- 选择器中类名越多优先级越高。
- 当选择器中类名相同时,选择器的优先级与声明的先后顺序有关,后声明的会覆盖先声明的。
优先级计算可见第七节
例如下面这个div标签,有三个类名分别是one two three
<div class="one two three">测试</div>
当声明如下样式时,文本的颜色为红色
.one {
color: blue
}
.three {
color: green;
}
.two {
color: red;
}
</style>
当声明如下样式时,文本的颜色为红色
.one.two {
color: blue
}
.two.three {
color: green;
}
.three.one {
color: red;
}
上述两个例子说明,当选择器中类名个数相同时,后声明的样式优先级更高。
当样式声明如下时,文本的颜色为蓝色,这说明选择器中类名个数越多优先级越高。
.one.two.three {
color: blue
}
.two.three {
color: green;
}
.three {
color: red;
}
1.4 ID选择器(ID Selector)
ID选择器以#
开头,选择文档中某个设定了id的元素。因为文档中的每个标签的id
属性唯一。基本语法如下:
#id {
属性1: 属性值1;
属性2: 属性值2;
……
}
可以在 ID 前面加上标签选择器,只指向元素和 ID 都匹配的元素。如下:
h1#heading {
color: rebeccapurple;
}
四种基础选择器的优先级为: ID选择器 > 类选择器 > 标签选择器 > 全局选择器
二、属性选择器(Attribute Selector)
HTML中每个元素都可以带有属性,在CSS中,可以通过属性选择器选中带有特定属性的元素。
2.1 存否选择器
存否选择器基于一个元素是否存在该属性来匹配。基本语法如下:
/* 选中存在attr属性的标签 */
标签名[attr] {
}
如下列表:
<ul>
<li>item1</li>
<li class="item2">item2</li>
<li>item3</li>
<li>item2</li>
</ul>
声明如下样式
li[class] {
color: red;
}
因为第二个li
存在class
属性,所以仅item2颜色为红色。
2.2 值选择器
值选择器基于标签某个属性的值进行匹配,主要分为以下三种情况:
选择器 | 示例 | 描述 |
---|---|---|
[attr=value] | a[href="https://example.com"] | 匹配具有属性 attr,且值为 value 的元素 |
[attr~=value] | a[class~="special"] | 匹配具有属性 attr的元素,其值是以空格分隔的单词列表,其中一个恰好是 value |
[attr|=value] | a[lang|="zh"] | 匹配具有属性 attr的元素,其值为 value 或以 value 开始后面紧跟一个连字符(-) |
如下示例:
<ul>
<li class="item1">item1</li>
<li class="item2">item2</li>
<li class="item item3">item3</li>
<li class="item-item4">item4</li>
</ul>
声明如下样式:
li[class='item2'] {
color: red;
}
li[class~='item'] {
color: blue;
}
li[class|='item'] {
color: green;
}
其中:
li[class='item2']
:匹配class
属性值为item2
的元素,所以选择了第二项。li[class~='item']
:匹配class
属性值中包含item
的元素,所以选择了第三项。li[class|='item']
:匹配class
属性值以item
开头且后面紧跟连字符(-)的元素,所以选择了第四项。
此外,
2.3 子字符串匹配选择器
该类选择器通过属性的值的子字符串的匹配。
选择器 | 示例 | 描述 |
---|---|---|
[attr^=value] | a[class^="box"] | 匹配具有属性 attr,且值以 value 开头的元素 |
[attr$=value] | a[class$="box"] | 匹配具有属性 attr,且值以 value 结尾的元素 |
[attr*=value] | a[class*="box"] | 匹配具有属性 attr,且值中包含 value 的元素 |
注意:如果value
为空字符串,则选择器不代表任何内容。
如下示例:
<ul>
<li class="a-item">item1</li>
<li class="item-a">item2</li>
</ul>
声明如下样式:
li[class^='a'] {
color: red;
}
li[class$='a'] {
color: blue;
}
li[class*='item'] {
font-size: 20px;
}
其中:
li[class^='a']
:匹配class
属性值以a
开头的元素,所以选择了第一项。li[class~='item']
:匹配class
属性值以a
结尾的元素,所以选择了第二项。li[class|='item']
:匹配class
属性值中存在子字符串为item
的元素,所以选择了第一、第二项。
注意:子字符串匹配选择器进行匹配时,会将整个属性值字符串作为一个对象来匹配。例如:某个标签
class
属性为"name1 name2"
时,不会逐个对"name1"
和"name2"
进行匹配,而是对"name1 name2"
进行匹配。
假设将li
的类名改成如下形式,那么li[class^='a']
和li[class$='a']
都不能选中元素。
<ul>
<li class="test a-item">item1</li>
<li class="item-a test">item2</li>
</ul>
2.4 忽略大小写
如果你想在大小写不敏感的情况下,匹配属性值的话,你可以在闭合括号之前,使用i
值。这个标记告诉浏览器,要以大小写不敏感的方式匹配 ASCII 字符。例如:
li[class^='a' i] {
color: red;
}
该种方式对以上五种和匹配属性值的选择器都适用。
2.5 多属性选择器
多个属性选择器可用于表示一个元素的多个属性,或同一属性的多个条件。如下示例:
/* 匹配 class 属性值以 "item" 开头,以 "red" 结尾的 li 元素 */
li[class^="item"][class$="red"]
/* 匹配 class 属性值为 "juejin",href 属性值为 "www.juejin.cn" 的 a 元素 */
a[class="juejin"][href="www.juejin.cn"]
注意:多属性选择器表示多个条件同时满足,在逻辑运算中是与(&)的关系。
2.6 属性选择器和命名空间
属性选择器的命名空间前缀书写方式有所不同,如下所示:
@namespace foo "http://www.example.com";
/* 仅匹配“http://www.example.com”命名空间中具有属性 att 且值为“val”的元素 */
[foo|att=val] { color: blue }
/* 匹配具有属性 att 的元素,而不管该属性的命名空间(包括没有命名空间) */
[*|att] { color: yellow }
/* 只匹配具有属性 att 且该属性不在命名空间中的元素 */
[|att] { color: green }
[att] { color: green }
三、伪类(Pseudo-class)
CSS伪类是添加到选择器的关键字,它用于选择处于特定状态的元素,比如当它们是这一类型的第一个元素时,或者是当鼠标指针悬浮在元素上面的时候。
伪类由冒号(:
)后跟着伪类名称组成,例如:
selector:pseudo-class-name {
property: value;
}
3.1 动态伪类
动态伪类不会出现在文档源或文档树中
(1)链接伪类
选择器 | 示例描述 |
---|---|
:link | 选择所有未被访问过的链接 |
:visited | 选择所有已被访问过的链接 |
:any-link | 匹配一个链接的:link 和:visited 状态。 |
:local-link | 匹配指向和当前文档同一网站页面的链接。 |
一段时间后,用户代理可能会选择将已访问的链接返回到(未访问的)
link
状态
:link
和:visited
是针对链接而言的,并非针对<a>
标签。如下两个链接,href
属性相同:
<a href="https://m.baidu.com/">链接1</a>
<a href="https://m.baidu.com/">链接2</a>
设置访问过的链接颜色为orange
a:visited{
color: orange;
}
当点击链接1后,链接1和链接2都会变成orange
,说明这个伪类是针对链接地址的,而非标签。
(2)用户操作伪类
选择器 | 描述 |
---|---|
:hover | 匹配指针设备指定的元素(鼠标指针悬停其上) |
:active | 匹配被激活的元素(鼠标左键按下未弹起时) |
:focus | 匹配获得焦点的元素(当用户点击或轻触一个元素或使用键盘的 Tab 键选择它时,它会被触发。例如:表单输入或select被点击) |
:focus-visible | 当元素有焦点,且焦点对用户可见的时候匹配。这个选择器可以有效地根据用户的输入方式 (鼠标 vs 键盘) 展示不同形式的焦点。 |
:focus-within | 匹配有焦点的元素,以及子代元素有焦点的元素 |
注意:当某个父元素应用了:hover
伪类,当鼠标指向其子元素时,也会被选中。
如下示例中,当鼠标悬于子元素时,父元素的背景色也会变成red
<style>
.father {
width: 200px;
height: 200px;
background: pink;
}
.father:hover {
background: red;
}
.child{
width: 100px;
height: 100px;
background: #000;
}
</style>
<div class="father">
<div class="child"></div>
</div>
注意: 当一个元素匹配多个伪类时,声明必须遵循以下顺序:
LVHA 顺序::link
—:visited
—:hover
—:active
3.2 目标伪类
选择器 | 描述 |
---|---|
:target | 代表一个唯一的页面元素 (目标元素),其id 与当前 URL 片段匹配 |
有些URI指的是资源中的一个位置。这种 URI 以 #
结尾,后跟锚标识符(称为片段标识符)。
带有片段标识符的 URI 链接到文档中的特定元素,称为目标元素。例如,这是一个指向 HTML 文档中名为 section_2 的锚点的 URI:http://example.com/html/top.html#section_2
目标元素可以用 :target
伪类表示,例如:p:target
表示选择<p>
元素,且是引用URI的目标元素。设置的样式只有当跳转到该元素时才会作用到该元素。
3.3 语言伪类
选择器 | 描述 |
---|---|
:lang(C) | 基于元素语言来匹配页面元素 |
如果文档语言规定了如何确定一个元素的人类语言,那么就有可能根据元素的语言来编写表示该元素的选择器
伪类 :lang(C)
表示使用语言"C"中的元素。即元素的语言值等于标识符 C,或以标识符 C 开头,紧跟“-”。且在在 ASCII 范围内匹配时不区分大小写。标识符 C 不必是有效的语言名称。
但是标识符C必须是有效的CSS标识符,且不能为空,否则选择器无效。
注意:
lang(C)
与[lang|=C]
的区别
lang(C)
是根据文档的语义来进行比较的[lang|=C]
是根据元素的lang
属性来比较的
如下例子中,:lang(fr)
能够选中 <body>
和 <p>
元素,而[lang|=fr]
只能选中<body>
元素,因为<p>
元素中没有lang
属性。
<body lang=fr>
<p>Je suis français.</p>
</body>
3.4 UI状态伪类
用于设置元素在不同用户操作过程中的状态样式
选择器 | 描述 |
---|---|
autofill | 在浏览器自动填充表单中的 <input> 元素的值时匹配该 input 元素。如果用户编辑了该字段,则该类将不再匹配 |
:checked | 匹配每个被选中的表单元素(即处于选中状态的radio, checkbox 或 select 元素中的option 元素。) |
:default | 匹配一组相关元素中的默认表单元素。(该选择器可以在 <button> , <input type="checkbox"> , <input type="radio"> , 以及 <option> 上使用),表示默认选中的选项 |
:indeterminate | 匹配状态不确定的表单元素,常用于复选框 |
:disabled | 匹配每个被禁用的表单元素(如果一个元素不能被激活(如选择、点击或接受文本输入)或获取焦点,则该元素处于被禁用状态) |
:enable | 匹配每个已启用的表单元素 (如果元素可以被激活(例如被选择、单击、输入文本等),或者能够获得焦点,那么它就是启用的) |
:in-range | 选择具有指定范围内的值的表单元素(仅适用于带有 min 和/或 max 属性的 input 元素, 例如<input type="number"> ) |
:out-of-range | 选择具有指定范围外的值的表单元素(仅适用于带有 min 和/或 max 属性的 input 元素, 例如<input type="number"> ) |
:invalid | 用来选择任何未通过验证的<form> 、<fieldset> 、<input> 或其他表单元素。 |
:valid | 表示内容验证正确的<input> 或其他 <form> 元素 |
:placeholder-shown | 表示当前显示占位符文本的任何 <input> 或 <textarea> 元素。(当输入使得占位符文本消失后则不被选中,该伪类并非表示是否设置了placeholder属性) |
:option | 表示任意没有required 属性的 <input> 、<select> 或 <textarea> 元素 |
:required | 表示任意设置了required 属性的 <input> 、<select> 或 <textarea> 元素 |
:read-only | 选中指定了 read-only 属性的元素 |
:read-write | 选中未指定 read-only 属性的元素 |
3.5 结构伪类
选择器引入了结构伪类的概念,以允许基于位于文档树中但不能由其他简单选择器或组合器表示的额外信息进行选择。
(1)树结构伪类
选择器 | 描述 |
---|---|
:root | 匹配文档树的根元素。对于 HTML4 来说, :root 表示 <html> 元素,除了优先级更高之外,与 html 选择器相同 |
:empty | 用于选择不包含任何子元素的元素。子元素可以是元素节点或文本(包括空格)。但是注释、处理指令和 CSS content 不会影响元素是否被认定为空。 |
(2)位置伪类
选择器 | 示例 | 示例描述 |
---|---|---|
:first-child | p:first-child | 选中所有<p> 元素父元素的首个子元素(仅当首个子元素为<p> 才能生效),等价于 p:nth-child(1) |
:last-child | p:last-child | 选中所有<p> 元素父元素的最后一个子元素(仅当最后一个子元素为<p> 才能生效),等价于 p:nth-last-child(1) |
:nth-child(N) | p:nth-child(2) | 选中所有<p> 元素父元素的第二个子元素(仅当第二个子元素为<p> 才能生效) |
:nth-last-child(N) | p:nth-last-child(2) | 选中所有<p> 元素父元素的倒数第二个子元素(仅当倒数第二个子元素为<p> 才能生效) |
:first-of-type | p:first-of-type | 选中所有<p> 元素父元素的首个子<p> 元素,等价于 p:nth-of-type(1) |
:last-of-type | p:last-of-type | 选中所有<p> 元素父元素的最后一个子<p> 元素,等价于 p:nth-last-of-type(1) |
:nth-of-type(N) | p:first-of-type | 选中所有<p> 元素父元素的第二个子<p> 元素 |
:nth-last-of-type(N) | p:first-of-type | 选中所有<p> 元素父元素的倒数第二个子<p> 元素 |
上述伪类可以分为两部分:
:first-child
、:last-child
、:nth-child(N)
、:nth-last-child(N)
:这些伪类中所指定的位置是相对于父元素的所有子元素而言,并且需要保证指定位置的元素是对应类型的元素才可选中。- 应用场景:常用于父元素中包含多个相同元素,选取相同元素中的第一个时。常用于列表或表格。
:first-of-type
、:last-of-type
、:nth-of-type(N)
、:nth-last-of-type(N)
:这些伪类中指定的位置是相对于父元素中特定类型的子元素而言的。
我们可以看以下例子来理解,假设有如下结构和样式:
<head>
<style>
.wrapper {
display: flex;
}
.box {
margin-right: 20px;
padding: 10px 20px;
width: 150px;
border: 2px solid black;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="box">
div1
<h4>第一个子元素:h4</h4>
<p>第二个子元素:p1</p>
<p>第三个子元素:p2</p>
<p>第四个子元素:p3</p>
</div>
<div class="box">
div2
<p>第一个子元素:p1</p>
<h4>第二个子元素:h4</h4>
<p>第三个子元素:p2</p>
<p>第四个子元素:p3</p>
</div>
<div class="box">
div3
<p>第一个子元素:p1</p>
<p>第二个子元素:p2</p>
<h4>第三个子元素:h4</h4>
<p>第四个子元素:p3</p>
</div>
<div class="box">
div4
<p>第一个子元素:p1</p>
<p>第二个子元素:p2</p>
<p>第三个子元素:p3</p>
<h4>第四个子元素:h4</h4>
</div>
</div>
</body>
初始状态状态如下:
a. :first-child
p:first-child{
color: red;
}
从上图可以看出,只有div2,div3,div4中的 p1 表现为红色,说明p:first-child
选中的是<p>
元素父元素的首个标签,且仅当首个标签为<p>
才会生效。div1 中的首个子元素并非<p>
,所以 div1 中的 p1 不会表现为红色。
b. :first-of-type
p:first-of-type{
color: red;
}
从上图可以看出,div1,div2,div3,div4中的 p1 都表现为红色,这说明与p:first-child
不同的在于p:first-of-type
选中的是<p>
元素父元素的子元素中所有<p>
元素的第一个。
c. :nth-child(n)
p:nth-child(2){
color: red;
}
:nth-child(n)
和:first-child
作用类似,只不过:nth-child(n)
能指定是第几个子元素。如上图所示,每个div中第二个子元素为<p>
时,都表现为红色。
此外,当索引 n 超过子元素个数时,不会选中任何元素。
c. :nth-of-type(n)
p:nth-of-type(2){
color: red;
}
:nth-of-type(n)
和:first-of-type
作用类似,但是:nth-of-type(n)
能指定是第几个。如上图所示,每个div中的第二个<p>
元素都表现为红色。
此外,当索引 n 超过特定子元素个数时,不会选中任何元素。
:last-child
、:nth-last-child(N)
、:last-of-type
、:nth-last-of-type(N)
这里就不一一示例了,只不过这些是逆序的,从最后一个子元素开始计数。
注意:对于伪类
:nth-child(N)
、:nth-last-child(N)
、:nth-of-type(N)
、:nth-last-of-type(N)
中的参数N
一般都是传一个大于0的整数,表示第几个或倒数第几个子元素。但是CSS规范中参数N
的取值并非只有大于0的整数,而是定义为an + b
,表示第an + b
子元素,其中 a、b 必须为整数(包括0、负值、正值),n为0和正整数。例如:li:nth-child(2n + 1)
表示第1、3、5......个子元素。则参数取值如下:
an + b
: a、b均不为0,表示 b、a + b、2a+b .......b
:a为0,b不为0,其中0值可以省略,表示 ban
:a不为0,b为0,其中0值可以省略,表示0、n、2n ......odd
:等价于2n+1
even
:等价于2n
此外,子元素的索引从1开始,如果索引为负值或者超出范围,则选中不了任何元素。
(3):only-child
和 only-of-type
选择器 | 描述 |
---|---|
:only-child | 匹配没有兄弟元素的元素。 |
:only-of-type | 匹配兄弟元素中某类型仅有的元素 |
:only-child
和 :only-of-type
是和兄弟元素相关的两个伪类,具体效果如下例所示:
<head>
<style>
.wrapper {
display: flex;
}
.box {
margin-right: 20px;
padding: 10px 20px;
width: 150px;
border: 2px solid black;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="wrapper">
<div class="box">
div1
<h4>标题</h4>
<p>段落</p>
</div>
<div class="box">
div2
<h4>标题</h4>
</div>
</div>
</div>
</body>
当我们添加如下样式时:
h4:only-child {
color: red;
}
如图所示,只有div2中的<h4>
呈现红色,因为:only-child
选中的是没有兄弟元素的元素,而 div1 中的<h4>
拥有兄弟元素<p>
。
当我们添加如下样式时:
h4:only-of-type {
color: red;
}
如图所示,只有div1、div2中的<h4>
呈现红色,因为:only-of-type
选中的类型仅有的元素,而 div1 、div2 中都只有一个<h4>
元素,所以都被选中了。
3.4 函数式伪类
选择器 | 描述 |
---|---|
:not() | 用来匹配不符合一组选择器的元素。由于它的作用是防止特定的元素被选中,它也被称为反选伪类 |
:has() | 表示一个元素,如果作为参数传递的任何相对选择器在锚定到该元素时,至少匹配一个元素 |
:is() | 以选择器列表作为参数,并选择该列表中任意一个选择器可以选择的元素 |
:where() | 接受选择器列表作为它的参数,将会选择所有能被该选择器列表中任何一条规则选中的元素。 |
(1)否定伪类(:not()
)
否定伪类 :not(X)
是一个函数符号,以一个简单的选择器(不包括否定伪类本身)作为参数。它表示一个未由其参数表示的元素。
否定不能嵌套; :not(:not(...))
无效。如果传递给 :not()
伪类的选择器无效或者浏览器不支持,则整个规则都将是无效的。
可以同时否定多个选择器。例如::not(.foo, .bar)
等同于 :not(.foo):not(.bar)
/* 选择所有非 disabled 状态的按钮 */
button:not([disabled])
/* 选择除 p 之外的所有元素*/
*:not(p)
/*选择 html 中所有非链接元素,因为访问过和未访问都排除*/
html|*:not(:link):not(:visited)
(2):has()
:has()
表示一个元素,如果作为参数传递的任何相对选择器在锚定到该元素时,至少匹配一个元素。
:has()
的 参数是一个可容错相对选择器列表,即 选择器列表(以逗号分隔的多个选择器所组成的列表)中的一个选择器无法解析时,不正确或不受支持的选择器将被忽略,而其他的则将被正常使用。
:has()
伪类不能被嵌套在另一个 :has()
内。
如下代码,我们可通过h1:has(+ h2)
选中第一个<h1>
标签,因为只有第一个<h1>
标签有紧跟其后邻接<h2>
元素。
<div>
<h1 class="test">h1-1</h1>
<h2>h2</h2>
<p>paragraph</p>
<h1>h1-2</h1>
</div>
(3)is()
is()
以选择器列表作为参数,并选择该列表中任意一个选择器可以选择的元素
:is()
的 参数也是一个可容错相对选择器列表,
:is()
通常可用于简化多级选择器,如下多级选择器书写非常繁琐
section section h1,
section article h1,
section aside h1,
section nav h1,
article section h1,
article article h1,
article aside h1,
article nav h1,
aside section h1,
aside article h1,
aside aside h1,
aside nav h1,
nav section h1,
nav article h1,
nav aside h1,
nav nav h1 {
font-size: 20px;
}
可以简化为:
:is(section, article, aside, nav) :is(section, article, aside, nav) h1 {
font-size: 20px;
}
(4):where()
:where()
接受选择器列表作为它的参数,将会选择所有能被该选择器列表中任何一条规则选中的元素
:where()
和 :is()
作用基本相同,但是的不同之处在于,:where()
的优先级总是为 0,但是 :is()
的优先级是由它的选择器列表中优先级最高选择器决定的。
注意:
(1):has()
、:is()
、:where()
的参数是可容错选择器列表,会忽略列表中的无效选择器。而:not()
得选择器列表参数中存在无效选择器时,则整个规则无效。
(2):not()
、:has()
、:is()
的优先级由参数中的选择器列表决定,具体计算方式见第七节,而:where()
的优先级始终为0.
3.5 资源状体伪类
选择器 | 描述 |
---|---|
:playing | 匹配代表音频、视频或者相似的能“播放”或者“暂停”的资源的,且正在“播放”的元素。 |
:paused | 匹配代表音频、视频或者相似的能“播放”或者“暂停”的资源的,且正在“暂停”的元素。 |
3.6 时间相关伪类
选择器 | 描述 |
---|---|
:current | 匹配当前显示的元素或元素的祖先。 |
:future | 匹配任何完全出现在与 :current 匹配的元素之后的元素。 |
:past | 配任何完全出现在与 :current 匹配的元素之前的元素 |
3.7 打印相关伪类
选择器 | 描述 |
---|---|
:left | 需要和@规则 @page 配套使用,对打印文档的左侧页设置 CSS 样式。 |
:right | @规则 @page 一起配套使用,表示打印文档的所有右页。。 |
3.8 其他伪类
选择器 | 描述 |
---|---|
:defined | 表示任何已定义的元素。这包括任何浏览器内置的标准元素以及已成功定义的自定义元素 |
:dir() (实验中) | :dir() 伪类匹配特定文字书写方向的元素。在 HTML 中,文字方向由dir 属性决定。其他的文档类型可能有其他定义文字方向的方法。 |
:fullscreen() | 匹配当前处于全屏模式的所有元素。如果有多个元素被放置在全屏模式下,则此选择器将匹配所有这些元素。 |
host() | 选择包含其内部使用的 CSS 的 shadow DOM 的根元素 |
:modal() | 匹配的元素处于一种状态,在这种状态下,它排除了与外部元素的所有互动,直到互动被取消 |
:scope | 它表示作为选择器要匹配的参考点的元素 |
四、伪元素(Pseudo-element)
伪元素是一个附加至选择器末的关键词,允许你对被选择元素的特定部分修改样式。基本语法如下:
selector::pseudo-element {
property: value;
}
一个选择器中只能使用一个伪元素。伪元素必须紧跟在语句中的简单选择器/基础选择器之后。
4.1 ::after
和::before
伪元素 | 描述 |
---|---|
::after | 用来创建一个伪元素,作为已选中元素的最后一个子元素 |
::before | 创建一个伪元素,其将成为匹配选中的元素的第一个子元素 |
例如我们想给某段文本加上引用标记: HTML
<p>给这段文本加上引用标记</p>
CSS
p::before {
content: "《";
color: red;
}
p::after {
content: "》";
color: blue;
}
4.2 ::first-line
和 ::first-letter
伪元素 | 描述 |
---|---|
::first-line | 在某块级元素的第一行应用样式。第一行的长度取决于很多因素,包括元素宽度,文档宽度和文本的文字大小。 |
::first-letter | 会选中某块级元素第一行的第一个字母,并且文字所处的行之前没有其他内容(如图片和内联的表格) |
(1)::first-line
在 CSS 中,::first-line 伪元素只有在附加到块状容器(例如block box
, inline-block
, table-caption
, table-cell
)时才会起作用。在这种情况下,它指的是该容器的第一个格式化行。如下行级元素就无法应用:
<span>这是一个行级元素</span>
元素的第一个格式化行可能出现在同一流中的块级后代内(即,由于浮动或定位而未超出流的块级后代)。如下代码中的<div>
的第一行就是p
的第一行“p-line”。
<div>
<p>p-line</p>
</div>
换个角度来看:如下代码,如果同时设置了div::first-line
和p::first-line
<DIV>
<P>First paragraph</P>
<P>Second paragraph</P>
</DIV>
可以等价为
<DIV>
<P><DIV::first-line><P::first-line>First paragraph</P::first-line></DIV::first-line></P>
<P><P::first-line>Second paragraph</P::first-line></P>
</DIV>
table-cell
或 inline-block
的第一行不能是祖先元素的第一行格式化行。如下代码中<div>
的第一行是“div-line”,而不是<p>
的第一行。
<div>
<p style="display=inline-block">p-line<br/>haha</p>
div-line
</div>
以下 CSS 属性适用于 ::first-line 伪元素:字体属性
、颜色属性
、背景属性
、word-spacing
’, ‘letter-spacing
’, ‘text-decoration
’, ‘text-transform
’, ‘line-height
’
在 CSS 继承过程中,出现在第一行的子元素部分仅从 ::first-line 伪元素继承适用于 ::first-line 伪元素的属性。对于所有其他属性,继承来自第一行伪元素的非伪元素父元素。 (未出现在第一行的子元素部分始终继承自该子元素的父元素。
(2)::first-letter
::first-letter
伪元素表示元素的第一个字母,如果它的行中没有任何其他内容(例如图像或内联表)。如下代码中,div::first-letter
无法选中字母 “ H”因为它前面存在行内标签<span>
。
<div>
<span></span>Hello
</div>
在第一个字母之前或之后的标点符号应包括在内。如下代码中div::first-letter
选中的则是"H'
<div>"H'ello</div>
首字母可以是数字如下代码中div::first-letter
选中的则是1
<div>1234</div>
在某些情况下,::first-letter 伪元素不应只包含一行中的第一个非标点字符。例如,组合字符必须与其基本字符保持一致。此外,某些语言可能有关于如何处理某些字母组合的特定规则
first-letter
必须包含在 first-line
中,如下代码,如果同时设置了p::first-line
和p::first-letter
<P>Some text that ends up on two lines</P>
那么可以等价为:
<P>
<P::first-line>
<P::first-letter>
S
</P::first-letter>ome text that
</P::first-line>
ends up on two lines
</P>
在 CSS 中,::first-letter
伪元素适用于类似块的容器,例如:block
, list-item
, table-cell
, table-caption
, inline-block
。未来可能支持更多类型的容器。
::first-letter
伪元素可用于所有此类包含文本的元素,或在包含文本的同一流中具有后代的元素。
在 CSS 中,table-cell
或 inline-block
的首字母不能是祖先元素的首字母。如下代码中,div::first-letter
就无法选中任何字母。
<div>
<p style="display: inline-block;">Hello</p>World
</div>
在 CSS 中,如果其“float”属性为“none”,则 ::first-line 伪元素类似于行内级元素;否则,它类似于浮动元素。以下属性适用于 ::first-letter 伪元素:字体属性
、text-decoration
、text-transform
、letter-spacing
、word-spacing
(适当时)、line-height
、float
、vertical-align
(仅当'float'为'none'时)、marigin属性
、padding属性
、border属性
、颜色属性
、背景属性
4.3 其他伪元素
伪元素 | 描述 |
---|---|
::file-selector-button | 表示type="file" 的 <input> 的按钮 |
::marker | 匹配列表的标记框(通常为一个符号或数字)。它作用在任何设置了 display: list-item 的元素或伪元素::上,例如 <li> 和 <summary> 元素。 |
::selection | CSS 伪元素应用于文档中被用户高亮的部分(比如使用鼠标或其他选择设备选中的部分)。 |
::slotted() | 于选定那些被放在 HTML 模板中的元素 |
::part() | 表示在阴影树中任何匹配 part 属性的元素。 |
五、组合选择器(Combinator)
5.1 后代选择器(Descendant)
后代选择器又称包含选择器,可以选择父元素里面的子元素。其写法就是把外层标签写在前面,内层标签写在后面,中间用空格分隔。当标签发生嵌套时,内层标签就成为外层标签的后代。基本语法如下:
元素1 元素2 {
}
其中:
- 元素1 和 元素之间用空格隔开
- 元素1是父级元素,元素2可以是子元素,也可以是孙元素,只要是元素1的后代即可,最终选择的是元素2
5.2 子代选择器(Child)
子选择器只能选择作为某元素的最近一级子元素,简单可理解为选亲儿子元素。基本语法如下:
元素1>元素2 {
}
- 元素1 和元素2 之间用 大于号(>) 隔开
- 元素1 是父级,元素2 是子级,最终选择的是元素2
- 元素2必须是亲儿子,其孙子、重孙之类的都不管。也可以称其为亲儿子选择器。(注意:是选择所有的儿亲儿子)
如下例,比较后代选择器和子代选择器的区别:
<article>
<div>
<p>p1</p>
</div>
<p>p2</p>
</article>
当采用后代选择器选择<article>
元素的所有后代<p>
元素时,只要是<article>
元素的后代都会被选中。
article p {
color: red;
}
当采用子代选择器选择<article>
元素的所有后代<p>
元素时,只有<article>
元素的直接子元素才会被选中。
article>p {
color: red;
}
5.3 邻接兄弟选择器(Next-sibling)
邻接兄弟选择器(+
)用来选中恰好处于另一个在继承关系上紧跟其后的元素。
元素1+元素2 {
}
- 元素1 和元素2 之间用 加号(+) 隔开
- 元素2紧跟于元素1之后,否则无法选中
5.4 后续兄弟选择器(Subsequent-sibling)
如果你想选中一个元素的兄弟元素,即使它们不直接相邻,你还是可以使用通用兄弟关系选择器(~
)
元素1~元素2 {
}
- 元素1 和元素2 之间用 代字号(~) 隔开
- 元素1 和 元素2 之间是兄弟,并不一定要紧邻
如下例,比较邻接兄弟选择器和通用兄弟选择器的区别:
<article>
<p>p1</p>
<div>div</div>
<p>p2</p>
<p>p3</p>
</article>
当采用邻接兄弟选择器选择<div>
元素的邻接<p>
元素时,当存在紧随<div>
元素其后的<p>
元素才会被选中。
div+p {
color: red;
}
当采用通用兄弟选择器选择<div>
元素的邻接<p>
元素时,<div>
元素后处于同一层级的<p>
元素都会被选中。
div~p {
color: red;
}
注意:以上四种组合符,空格(
)、大于号(
>
)、加号(+
)、代字号(~
)周围允许出现空白,但仅限于“空格”(U+0020)、“制表符”(U+0009)、“换行符”(U+000A)、“回车符”(U+000D)和“换页符”(U+000C)。
六、 选择器组(Group)
选择器组也称并集选择器,可以选择多组标签,同时为他们定义相同的样式。通常用于集体声明
并集选择器是个选择器通过**英文逗号(,)**连接而成,任何形式的选择器都可以作为并集选择器的一部分
元素1, 元素2 {
}
注意:选择器组中只要存在一个无效选择器,那么整个选择器组都将无效。如下示例中,如果单独声明的话,那么只有h2..foo
选择器无效,如果通过选择器组的形式声明,那么整个h1, h2..foo, h3
都无效
单独声明
h1 { font-family: sans-serif }
h2..foo { font-family: sans-serif }
h3 { font-family: sans-serif }
选择器组
h1, h2..foo, h3 { font-family: sans-serif }
七、选择器优先级(Specificity)
有关CSS选择器的优先级,很多资料或者帖子都是通过一种排序的方式给出,但这种方式难以记忆而且很多情况下与实际情况并不符合,下面给出CSS规范中对于选择器优先级的计算方法。
7.1 选择器的优先级计算方法
- 统计选择器中ID选择器的个数(=a)
- 统计选择器中类选择器、属性选择器、伪类的个数(= b)
- 统计选择器中类型选择器和伪元素的数量(= c)
- 忽略通用选择器
- 否定伪类中的选择器像其他任何选择器一样被计数,但否定本身不被视为伪类。
连接三个数字 a-b-c(在具有大基数的数字系统中)就得到了选择器的优先级
* /* a=0 b=0 c=0 -> specificity = 0 */
LI /* a=0 b=0 c=1 -> specificity = 1 */
UL LI /* a=0 b=0 c=2 -> specificity = 2 */
UL OL+LI /* a=0 b=0 c=3 -> specificity = 3 */
H1 + *[REL=up] /* a=0 b=1 c=1 -> specificity = 11 */
UL OL LI.red /* a=0 b=1 c=3 -> specificity = 13 */
LI.red.level /* a=0 b=2 c=1 -> specificity = 21 */
#x34y /* a=1 b=0 c=0 -> specificity = 100 */
#s12:not(FOO) /* a=1 b=0 c=1 -> specificity = 101 */
7.2 !important 例外规则
当在一个样式声明中使用一个 !important
规则时,此声明将覆盖任何其他声明。
注意:
!important
书写于某个属性声明之后,而并非某个单独的css属性
如下,<p>
标签字体大小为50px优先级最高。。
p { font-size: 50px !important; }
当两条相互冲突的带有 !important
规则的声明被应用到相同的元素上时,拥有更大优先级的声明将会被采用。如果优先级相同,后声明的会覆盖先声明的。
注意:虽然
!important
从技术方面能够提升优先级,但是使用!important
是一个坏习惯,应该尽量避免,因为这破坏了样式表中的固有的级联规则 使得调试找 bug 变得更加困难了
通常使用 !important
的场景如下:
- 覆盖内联样式
- 覆盖优先级高的选择器
7.3 优先级相同误区
当选择器优先级相同时,后声明的样式会覆盖先声明的。
这一点刚开始学习css时,都会了解到,但是这里将讨论一些看似优先级相同的情况。如下div
标签
<div class="test">测试</div>
添加样式为:
div[class='test'] {
color: red;
}
.test {
color: green;
}
对于本人而言,之前会这样分析:属性选择器和类选择器的优先级相同,优先级相同时后声明的会覆盖先声明的,所以最终<div>
中字体颜色为绿色(green)。但实际上字体颜色为红色(red)。
这是因为div[class='test']
和.test
的优先级并不相同,按7.1中的计算方法:
div[class='test']
:有1个类型选择器和1个属性选择器,所以优先级为11
.test
:等同于*.test
,*
直接忽略,只有一个类选择器,所以优先级为10
所以div[class='test']
的优先级高于.test
,故最终字体颜色表现为红色(red)。
如果做如下修改,那么最终<div>
中字体颜色为绿色(green)
div[class='test'] {
color: red;
}
div.test {
color: green;
}
因为div.test
的优先级和div[class='test']
相同。
综上:对于属性选择器、伪类选择器、伪元素选择器,在进行优先级计算时,不能与前面的其他选择器混在一起。
- 属性选择器:
[]
- 伪类:
:
- 伪元素:
::
7.4 总结
综合所有情况,样式的优先级可简单排列为:
!important
>内联样式
>ID选择器
>[类选择器、属性选择器、伪类]
>[类型选择器、伪元素]
>全局选择器
根据7.1和7.2中的规则,可将选择器的优先级定义成一个四位数iabc
i
:是否设置了important
,是(1),否(0)a
:ID选择器
个数b
:[类选择器、属性选择器、伪类]
个数c
:[类型选择器、伪元素]
个数
iabc
值越大,则选择器的优先级越高。
本文到这里就结束了,主要是记录对官方文档的学习,以及个人的一些简单理解。如有错误,欢迎指正。