07选择器进阶
基础篇学会了「点名」:标签、class、id。这一课把点名的功夫练到出神入化—— 按「亲戚关系」找(组合选择器)、按「随身证件」找(属性选择器)、按「排行」找(结构伪类)、 按「此刻状态」找(状态伪类),甚至凭空造零件(伪元素)。 最后用「优先级」一锤定音:规则打架时,到底听谁的。
一、组合选择器:四种「亲戚关系」
单独一个选择器只能描述「是谁」,组合选择器描述「和谁是什么关系」。
四个符号——空格、>、+、~——就是四种亲戚关系,
再加一个逗号管「分组」。
| 写法 | 名称 | 选中的是谁 | 记忆口诀 |
|---|---|---|---|
A B(空格) | 后代选择器 | A 里面任意层级的 B,隔多少层都算 | 「A 家里所有叫 B 的」 |
A > B | 子代选择器 | A 的直接孩子 B,孙子免谈 | 「A 的亲儿子」 |
A + B | 相邻兄弟 | 紧跟在 A 后面的第一个同级 B | 「A 身后紧跟的那位」 |
A ~ B | 通用兄弟 | A 后面的所有同级 B | 「A 身后全体兄弟」 |
A, B(逗号) | 分组选择器 | A 和 B 一起选中,共用一套样式 | 「你们俩一起上」 |
>」,下半场比「+ vs ~」。试试把 .box > p 的 > 删掉,看孙子级 p 也被染绿上半场:后代(空格)选所有层级,子代(>)只选直接子级
① 直接子级 p —— 空格 ✓ 且 > ✓ → 绿色
② 孙子级 p —— 只有空格 ✓ → 琥珀色
③ 曾孙级 p —— 还是只有空格 ✓ → 琥珀色
下半场:+ 只选紧邻的第一个,~ 选后面全部
参照物 h5
④ 紧邻的 p —— + ✓ 且 ~ ✓ → 紫底 + 紫左边框
⑤ 第二个 p —— 只 ~ ✓ → 紫左边框
⑥ 第三个 p —— 只 ~ ✓ → 紫左边框
⑦ div 里套着的 p —— 兄弟关系看的是 div,不是我 → 无命中
绿 = 两代选择器都命中 · 琥珀 = 仅空格命中 · 紫底 = + 命中 · 紫左边框 = ~ 命中
> 就别用空格:一是意图更明确(读者一眼知道只影响子级),二是性能更好(浏览器不用一层层往下翻)。改别人代码时,空格选择器改错一个层级,样式就会「莫名感染」。二、属性选择器:不用 class 也能精准点名
元素身上的属性——href、type、src、自定义的 data-*——
本身就是现成的「证件」。方括号 [ ] 就是查证件的窗口:
查得越细,选得越准,一个 class 都不用加。
| 写法 | 命中条件 | 典型用途 |
|---|---|---|
[href] | 有这个属性就行 | 所有带链接的 a |
[type="text"] | 属性值完全相等 | 只选文本框,跳过按钮和勾选框 |
[href^="https"] | 值以 https 开头 | 挑出所有外部链接 |
[href$=".pdf"] | 值以 .pdf 结尾 | 给文件下载链接加图标 |
[href*="runoob"] | 值里包含 runoob | 关键词模糊匹配 |
[data-tags~="css"] | 值包含独立词 css(空格分隔的完整单词) | 标签系统:一个属性塞多个标签 |
^="https" 改成 $=".com" 看命中变化按 href 特征挑链接
https://www.runoob.com ^="https" ✓ · *="runoob" ✓ https://developer.mozilla.org ^="https" ✓ css-cheatsheet.pdf $=".pdf" ✓ mailto:hi@example.com 都不命中 → 保持默认~=(整词匹配)vs *=(任意包含)
^ 像钉子钉在开头,$ 像尾巴收在结尾,* 是通配符表示随便包含。~= 最容易踩坑:它只认「空格分隔的完整单词」——标签写 css3 时,~="css" 选不中它,*="css" 却能。做标签筛选时想清楚要哪种。三、结构伪类:第几个孩子我说了算
「第 3 个 li」「偶数行」「每种类型的第一个」……结构伪类专管排行。 冒号开头,跟在选择器屁股后面,专治「不方便挨个加 class」的批量场景。
| 伪类 | 含义 | 高频场景 |
|---|---|---|
:first-child | 是父亲的第一个孩子 | 导航第一项去分隔线 |
:last-child | 是父亲的最后一个孩子 | 列表末项去底边框 |
:nth-child(n) | 第 n 个(从 1 数起) | 点名任意一位 |
:nth-child(odd) / (even) | 奇数 / 偶数位 | 表格斑马纹 |
:nth-child(3n+1) | 公式:第 1、4、7… 个 | 每 3 个换一组 |
:nth-last-child(n) | 从后往前数第 n 个 | 倒数第几条 |
:first-of-type | 同类型里的第一个 | 混排容器的救星(见下方坑) |
:nth-of-type(n) | 同类型里的第 n 个 | 每隔 2 张图片加边距 |
:only-child | 独生子:父亲只有它一个孩子 | 单条数据特殊排版 |
:nth-child 的 an+b 公式口算
an+b 里 n 从 0 开始自动递增(0、1、2、3…),把 n 逐个代进去,
算出来是几就选第几个。背下这几个常用公式就够应付八成场景:
| 公式 | 展开后是哪些(n = 0,1,2,3…) | 使用场景 |
|---|---|---|
| odd / 2n+1 | 第 1、3、5、7… 个 | 斑马纹的奇数行 |
| even / 2n | 第 2、4、6、8… 个 | 斑马纹的偶数行 |
| 3n | 第 3、6、9… 个 | 每行第 3 张卡片去掉右外边距 |
| 3n+1 | 第 1、4、7、10… 个 | 三列布局的每行开头 |
| n+4 | 第 4、5、6… 个(前 3 个不要) | 跳过前几条精选,选中其余 |
| -n+3 | 第 3、2、1 个(只选前 3 个) | 排行榜前三甲特殊样式 |
odd 改成 3n+1 看斑马纹变规律;下半场是 :first-child 的经典坑命中地图:条纹来自 odd/even,边框来自 first/last,虚线圈是 nth-child(3)
- 第 1 项first-child · odd
- 第 2 项even
- 第 3 项nth-child(3) · odd
- 第 4 项even
- 第 5 项odd
- 第 6 项even
- 第 7 项last-child · odd
经典坑:混排容器里,:first-child 认「总排行」,:first-of-type 认「分类型」
① 我是容器的第一个孩子 → p:first-child ✓(紫)
② 我是第一个 h5 → h5:first-of-type ✓(绿),但 h5:first-child ✗
③ 普通 p → 谁都不选
④ 第二个 h5 → 谁都不选
:first-child 的意思是「恰好是父亲的第一个孩子」,不是「第一个这种元素」。写了 h5:first-child 却死活不生效,先检查:h5 前面是不是还站着别的标签?是的话换 h5:first-of-type。nth-child 和 nth-of-type 同理:前者混着数,后者分开数。四、状态伪类:元素此刻的心情
同一个元素,不同时刻不同待遇:鼠标悬停时、正被按住时、获得焦点时、被勾选时、被禁用时…… 状态伪类让 CSS 能「看心情」办事,是交互反馈的地基。
| 伪类 | 什么时候命中 | 典型用法 |
|---|---|---|
:hover | 鼠标悬停在上面 | 按钮/链接变色、上浮 |
:active | 正被按住的那一下 | 按下缩小、加深,像真的压下去 |
:focus | 获得输入焦点(点击 / Tab 切入) | 输入框亮起描边 |
:focus-within | 自己或后代有焦点 | 表单里任意框被点,整个表单高亮 |
:checked | 勾选框 / 单选被选中 | 配合兄弟选择器做纯 CSS 开关 |
:disabled | 表单控件被禁用 | 置灰 + 禁止光标 |
:link / :visited | 没点过 / 已经点过的链接 | 已读链接变淡 |
:focus 和 :focus-within,悬停/按住按钮,勾选勾选框看 :checked + span 组合拳input[type="text"];勾选后的对勾是第 5 节的伪元素 ::after;:checked + span 用了第 1 节的相邻兄弟。选择器从来都是组合出场的,这也是它们真正的威力所在。五、伪元素:凭空造出「隐形零件」
伪类描述「状态」,伪元素更进一步——直接在元素内部
凭空生成一个假想的子元素。最常用的是 ::before 和
::after 这对双胞胎,分别站在内容的正前方和正后方。双冒号是 HTML5 时代的规范写法
(老代码里的单冒号也能跑)。
| 伪元素 | 管哪块 | 典型用法 |
|---|---|---|
::before | 内容前面的隐形盒子 | 引号、图标、装饰色块、清除浮动 |
::after | 内容后面的隐形盒子 | 闭合引号、「更多 »」箭头 |
::first-letter | 只管第一个字 | 杂志式首字下沉 |
::first-line | 只管第一行 | 导语第一行加粗变色 |
::selection | 鼠标划选中的文字 | 自定义选中背景色 |
::placeholder | 输入框的占位提示 | 提示文字变淡变小 |
::marker | 列表项的记号(圆点/数字) | 把圆点换成彩色方块 |
::selection 换色;把 content 删掉看伪元素直接消失杂志排版里常见的首字下沉(Drop Cap),靠 ::first-letter 一个伪元素就能实现—— 第一个字被放大、漂浮到段落左侧,正文自动环绕它排布。下面的引用块更妙: 试试用鼠标划选那段文字,选中的背景色会被 ::selection 换成琥珀色。
我前后的两个大引号,HTML 里一个字都没写——它们是 ::before 和 ::after 凭空生成的。不插文字也行:content 写空字符串,再用宽高和背景色, 就能画出装饰用的色块、分隔线、气泡小尾巴。
content 是伪元素的命门——忘了写 content,整个伪元素直接不显示。不想插内容就写 content: ""(画装饰图形的标准姿势)。另外 ::before / ::after 默认是行内元素:想设宽高、做定位,得先加 display: block(或 inline-block / position: absolute)。六、优先级:规则打架了,谁说了算
三条规则同时给一个元素上色,听谁的?CSS 有一套铁打的算法——权重(specificity)。 把选择器拆开数三档:(id 个数, class/属性/伪类个数, 标签/伪元素个数), 从左往右逐位比较,左边大的直接赢。
| 选择器 | 权重 | 地位 |
|---|---|---|
行内 style="…" | 1-0-0-0 | 写在标签上,尽量少用 |
#id | 0-1-0-0 | 一等公民,一票顶千军 |
.class / [attr] / :hover | 0-0-1-0 | 主力部队,日常靠它们 |
标签 / ::before | 0-0-0-1 | 基础兵,打底用 |
* / 组合符 + ~ > | 0-0-0-0 | 不计数,纯关系 |
!important | 核弹 | 同权重全灭,调试应急,别当饭吃 |
口算练习:这些选择器各是几比几
合上答案先自己数一遍——数 (id, class/属性/伪类, 标签/伪元素) 三档,再对照右边:
| 选择器 | 拆解 | 权重 |
|---|---|---|
p | 1 个标签 | 0-0-1 |
.nav li | 1 个 class + 1 个标签 | 0-1-1 |
.nav > .item:hover | 2 个 class + 1 个伪类 | 0-3-0 |
ul li.active a | 1 个 class + 3 个标签 | 0-1-3 |
#header .nav a | 1 个 id + 1 个 class + 1 个标签 | 1-1-1 |
input[type="text"]:focus | 1 个属性 + 1 个伪类 + 1 个标签 | 0-2-1 |
.list li:not(.empty) | 2 个 class + 1 个标签(:not 不计数,括号里的 .empty 计) | 0-2-1 |
#hero 规则删掉,看绿色 class 接管p0-0-1灰色 · 最弱.note0-1-0绿色 · 居中#hero1-0-0红底白字 · 完胜三条规则抢着给我上色——id 权重最高,我听 #hero 的
两条同权重规则盯着我:先写的浅紫、后写的深紫——后写的赢(层叠)
七、本章小结
- 组合:空格选所有后代、
>只选亲儿子、+紧邻一个、~后面全部、逗号分组共用。 - 属性:
[attr]有就行、=全等、^=开头、$=结尾、*=包含、~=整词(css3 ≠ css)。 - 结构伪类管排行:
nth-child系列混着数、of-type系列分类型数;:first-child必须真的是第一个孩子。 - 状态伪类管心情:hover / active / focus / checked / disabled;
:focus-within让整个容器感知焦点。 - 伪元素凭空造零件:::before / ::after 记得写 content;::first-letter 首字下沉;::selection 换选中色。
- 打架看权重:数 (id, class/属性/伪类, 标签/伪元素) 三档逐位比;同权重后写的赢;!important 是核弹不是常规武器。
nth-child(even) 打斑马纹,first-child 强调表头行;每个联系人写 data-dept="前端" 之类的属性,用属性选择器给不同部门染不同色;行 hover 高亮用 :hover;每行前面加一个部门色块——颜色本身用 ::before 画出来。全章武器一次用遍。