复合选择器、状态与层叠
真实页面不能为每个标签单独创建类。本节学习根据结构、属性和状态选择元素,并建立一套判断“为什么这条样式没有生效”的方法。
组合条件定位元素
后代选择器
下方是这张图的内联 HTML 示意。h1 与 em 之间的空格表示后代关系:
概念:
后代选择器又称为包含选择器
作用:
用来选择元素或元素组的 子孙后代
其写法就是把外层标签写在前面,内层标签写在后面,中间用 空格 分隔,先写父亲爷爷,在写儿子孙子。
父级 子级{属性:属性值;属性:属性值;}语法:
css.student-card p {color:red; font-size:16px;}空格表示选择
.student-card内部任意层级的p。html<article class="student-card"> <div> <p>这一段也会被选中。</p> </div> </article>
不要把选择器写得过长。.page .content .list .item .name 对结构依赖过强,页面稍作调整就可能失效。
子代选择器
下方是图片中的 h1 > em 示意。> 只选中直接子元素:
作用:
子元素选择器只能选择作为某元素 子元素 (亲儿子) 的元素。
其写法就是把父级标签写在前面,子级标签写在后面,中间跟一个
>进行连接语法:
css.main-nav > a {color: #ffffff;}>只匹配直接子元素,这里的子指的是亲儿子不包含孙子、重孙子之类。:html<nav class="main-nav"> <a href="/students">学员</a> <div> <a href="/students/import">导入</a> </div> </nav>上面的规则只选择第一个直接位于
nav下的链接。
交集选择器
我们可以给标签指定多个类名,从而达到更多的选择目的。
注意:
- 各个类名中间用空格隔开。
- 多类名选择器在后期布局比较复杂的情况下,还是较多使用的。
图片中的两种写法都是交集选择器,条件必须由同一个元素同时满足:
选择同一个元素的多个条件之间不加空格:
.status.is-active {
color: #16803c;
}
button.primary-button {
background-color: #1677ff;
}.status.is-active 表示同时拥有两个类;.status .is-active 表示后代关系。
并集选择器
图片用逗号把标签、ID 和类选择器合并,三类元素共享同一条声明:
多个选择器需要使用同一组声明时,用逗号组成并集选择器:
这张图还展示了并集选择器可以共用多条声明:
标签、类、ID 和其他组合选择器都可以参与分组。例如 .one, p, #test { color: #f00; } 会同时选中 .one、所有 p 和 #test,避免重复书写相同声明。
属性选择器
图片中的 a[name] 由标签名称和方括号中的属性条件组成:
input[required] {
border-color: #d97706;
}
input[type="search"] {
background-color: #ffffff;
}
[data-status="disabled"] {
color: #b42318;
}常见形式:
| 写法 | 含义 |
|---|---|
[required] | 拥有该属性 |
[type="search"] | 属性值完全相等 |
[class~="active"] | 空格分隔的属性值列表中包含该单词 |
基础项目优先使用类表达视觉状态;属性选择器适合表单类型、原生状态和确有含义的数据属性。
现代逻辑伪类
:is() 可以把多个选择器条件合并到一条规则中,同时保留参数中最高的特异度:
:is(.page-title, .dialog-title) {
color: #17233d;
}:where() 的写法相似,但特异度始终为 0,适合提供低优先级的基础规则:
:where(.page, .dialog) a {
color: #1677ff;
}这两个伪类都用于减少重复选择器,但不能把 :is() 和 :where() 当成完全相同的写法。
根据状态选择元素
链接伪类选择器
图片中的 :link 用于选择尚未访问的链接状态:
为了和我们刚才学的类选择器相区别
类选择器是一个点 比如 .demo {}
在 CSS 中,我们可以使用“超链接伪类”来定义超链接在鼠标点击的不同时期的样式。
语法:
cssa:link { … } a:visited { … } a:hover { … } a:active { … }说明:
| 伪类 | 说明 |
|---|---|
| a:link | 定义 a 元素未访问时的样式 |
| a:visited | 定义 a 元素访问后的样式 |
| a:hover | 定义鼠标经过 a 元素时的样式 |
| a:active | 定义鼠标点击激活时的样式 |
如果同时定义多个链接状态,通常按照 :link、:visited、:hover、:active 的 LVHA 顺序书写,避免后面的规则覆盖前面的规则。实际项目不一定需要定义全部四种状态。
- 多个伪类同时作用于同一个元素时,中间不加空格,例如
a:link:hover;空格表示后代关系。 - 因为
a链接浏览器具有默认样式,所以我们实际工作中都需要给链接单独指定样式。 - 实际工作开发中,我们很少写全四个状态,一般我们写法如下:
a {
/* a 是标签选择器 所有的链接 */
font-weight: 700;
font-size: 16px;
color: gray;
}
a:hover {
/* :hover 是链接伪类选择器 鼠标经过 */
color: red;
/* 鼠标经过的时候,由原来的 灰色 变成了红色 */
}用户操作伪类
伪类表示元素处于某种状态,以 : 开头。
.nav-link:hover {
background-color: #eef4ff;
}
.form-control:focus {
border-color: #1677ff;
outline: 3px solid rgb(22 119 255 / 18%);
}
.primary-button:disabled {
cursor: not-allowed;
opacity: 0.55;
}:hover:指针悬停。:focus:元素获得焦点。:disabled:表单控件被禁用。:checked:单选或复选控件被选中。
不要只设计 :hover。键盘用户需要清楚的焦点提示。现代项目也常用 :focus-visible:
.nav-link:focus-visible {
outline: 3px solid #fbbf24;
outline-offset: 2px;
}结构伪类
.student-table tbody tr:first-child {
font-weight: 600;
}
.student-table tbody tr:last-child {
border-bottom: 0;
}
.student-table tbody tr:nth-child(even) {
background-color: #f8fafc;
}:first-child:同级中的第一个子元素。:last-child:同级中的最后一个子元素。:nth-child(even):同级中的偶数位置。
位置是根据同一父元素下的全部兄弟元素计算的。复杂公式不属于本课程重点。
1、属性列表
| 选择符 | 简介 |
|---|---|
| E:first- child | 匹配父元素中的第一个子元素 E |
| E:last-child | 匹配父元素中最后一个 E 元索 |
| E:nth-child(m) | 匹配父元素中的第 n 个子元素 E |
| E:first-of-type | 指定类型 E 的第一个 |
| E:last-of-type | 指定类型 E 的最后一个 |
| E:nth-of-type(n) | 指定类型 E 的第 n 个 |
2、代码演示
ul li:first-child {background-color: lightseagreen;}
ul li:last-child {background-color: lightcoral;}
ul li:nth-child(3) {background-color: aqua;}nth-child 参数详解
1、nth-child 详解
- 注意:本质上就是选中第几个子元素
- n 可以是数字、关键字、公式
- n 如果是数字,就是选中第几个
- 常见的关键字有
even偶数、odd奇数 - 常见的公式如下 (如果 n 是公式,则从 0 开始计算)
- 但是第 0 个元素或者超出了元素的个数会被忽略
| 公式 | 取值 |
|---|---|
| 2n | 偶数 |
| 2n + 1 | 奇数 |
| 5n | 5 10 15 ... |
| n + 5 | 从第 5 个开始(包含第五个)到最后 |
| -n + 5 | 前 5 个(包含第五个) |
2、代码演示
/* 偶数 */
ul li:nth-child(even) { background-color: aquamarine; }
/* 奇数 */
ul li:nth-child(odd) { background-color: blueviolet; }
/*n 是公式,从 0 开始计算 */
ul li:nth-child(n) { background-color: lightcoral; }
/* 偶数 */
ul li:nth-child(2n) { background-color: lightskyblue; }
/* 奇数 */
ul li:nth-child(2n + 1) { background-color: lightsalmon; }
/* 选择第 0 5 10 15, 应该怎么选 */
ul li:nth-child(5n) { background-color: orangered; }
/* n + 5 就是从第 5 个开始往后选择 */
ul li:nth-child(n + 5) { background-color: peru; }
/* -n + 5 前五个 */
ul li:nth-child(-n + 5) { background-color: tan; }伪元素
| 选择符 | 简介 |
|---|---|
| ::before | 在元素内部的签名插入内容 |
| ::after | 在元素内部的后面插入内容 |
伪元素表示元素中的一个虚拟部分,使用 :::
.required-label::after {
content: " *";
color: #b42318;
}
.page-title::before {
content: "";
display: inline-block;
width: 4px;
height: 20px;
margin-right: 8px;
background-color: #1677ff;
}::before 和 ::after 依赖 content。它们适合装饰,不应承载只有屏幕上才有的关键业务信息。
判断最终生效的样式
层叠
图片中的两条规则都设置了 div 的颜色。后一条覆盖前一条的 color,但不会清除前一条的 font-size:
color: red;
font-size: 18px;
}
color: green;
}
概念:
所谓层叠性是指多种
CSS样式的叠加。是浏览器处理冲突的一个能力,如果一个属性通过两个相同选择器设置到同一个元素上,那么这个时候一个属性就会将另一个属性层叠掉
原则:
样式冲突时,不能只看哪条规则“离 HTML 更近”。浏览器会先判断声明的来源与重要性,再比较层叠层级、选择器特异度,最后才比较相同条件下的源码顺序。
样式不冲突时,不同声明可以同时生效;只有同一属性发生竞争时才需要判断层叠结果。
继承
图片中的 p 没有单独设置文字颜色和字号,会继承父元素 div 的这两项值:
color: red;
font-size: 18px;
}
<p>文本颜色</p>
</div>
概念:
子标签会继承父标签的某些样式,如文本颜色和字号。
想要设置一个可继承的属性,只需将它应用于父元素即可。
简单的理解就是:子承父业。
文字相关属性通常可以继承;背景、边框、外边距和宽高通常不会继承。开发者工具会标出继承来源。不要用“所有 CSS 都会继承”来理解页面。
注意:
恰当地使用继承可以简化代码,降低
CSS样式的复杂性。比如有很多子级孩子都需要某个样式,可以给父级指定一个,这些孩子继承过来就好了。- 子元素可以继承父元素的样式(text-,font-,line-这些元素开头的可以继承,以及color属性)
CSS 继承性口诀:龙生龙,凤生凤,老鼠生的孩子会打洞。
优先级
图片中两个选择器都匹配 <div class="box">。类选择器 .box 的特异度高于标签选择器 div,因此颜色取 green;字号只在 div 规则中声明,仍然生效:
color: green;
}
color: red;
font-size: 18px;
}
- 概念:
定义 CSS 样式时,经常会有两个或更多规则同时匹配同一个元素。选择器相同或特异度相近时,需要继续结合来源、重要性和源码顺序判断最终结果。
在不讨论来源、重要性和层叠层级的简化练习中,可以这样比较特异度:
行内样式 > ID 选择器 > 类/属性/伪类 > 元素/伪元素:where(.page, .dialog) a {
color: #1677ff;
}项目中遇到时知道它不会增加选择器优先级即可,不要求现在使用。
练习优先级判断
题目 1
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>第1题</title>
<style>
div div {color: blue;}
div {color: red;}
</style>
</head>
<body>
<div>
<div>
<div>
试问这行字体是什么颜色的?
</div>
</div>
</div>
</body>
</html>题目 2
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>第2题</title>
<style>
#father {color: red;}
p {color: blue;}
</style>
</head>
<body>
<div id="father">
<p>试问这行字体是什么颜色的?</p>
</div>
</body>
</html>题目 3
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
div div div div div div div div div div div div {color: red;}
.me {color: blue;}
</style>
</head>
<body>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div>
<div class="me">试问这行文字是什么颜色的</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>题目 4
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>第4题</title>
<style>
div p {color: red;}
#father {color: yellow;}
p.c2 {color: blue;}
</style>
</head>
<body>
<div id="father" class="c1">
<p class="c2">
试问这行字体是什么颜色的?
</p>
</div>
</body>
</html>题目 5
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.c1 .c2 div {color: blue;}
div #box3 {color: green;}
#box1 div {color: yellow;}
</style>
</head>
<body>
<div id="box1" class="c1">
<div id="box2" class="c2">
<div id="box3" class="c3">
文字
</div>
</div>
</div>
</body>
</html>题目 6
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>第6题</title>
<style>
#father #son {color: blue;}
#father p.c2 {color: black;}
div.c1 p.c2 {color: red;}
#father {color: green !important;}
/*!important 会改变声明优先级,不是让特异度变成无限大*/
p {color: green !important;}
</style>
</head>
<body>
<div id="father" class="c1">
<p id="son" class="c2" >
试问这行字体是什么颜色的?
</p>
</div>
</body>
</html>小结
- 组合选择器可以根据结构、多个条件和属性定位元素。
- 伪类表达状态,伪元素适合非关键装饰。
- 字体和颜色常会继承,盒模型相关属性通常不会。
- 样式冲突要按匹配、来源、优先级和顺序判断。
- 选择器应尽量短、稳定并围绕组件职责组织。
选择器与层叠练习源码
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>第6题</title>
<style>
#father #son {color: blue;}
#father p.c2 {color: black;}
div.c1 p.c2 {color: red;}
#father {color: green !important;}
/*!important 会改变声明优先级,不是让特异度变成无限大*/
p {color: green !important;}
</style>
</head>
<body>
<div id="father" class="c1">
<p id="son" class="c2">
试问这行字体是什么颜色的?
</p>
</div>
</body>
</html>