五组必会选择器

1. 类型 / class / id / 通配

p { }            /* 类型选择器:命中所有 p,权重 0,0,1 */
.card { }        /* class:权重 0,1,0 —— 日常主力 */
#header { }      /* id:权重 1,0,0 —— 别拿来写样式 */
* { }            /* 通配:命中所有元素,权重 0,只适合做重置 */
*, *::before, *::after { box-sizing: border-box; }  /* 唯一的正当用途 */

2. 组合子:空格、>、+、~

我是 .box 的直接子元素 → 同时被 .box p 和 .box > p 命中(黄底)。

我隔了一层 div → 只被 .box p 命中(无底色)。

第一个 h4(无样式)

紧邻的第二个 h4 → h4 + h4 命中,紫色

一个段落 这个 span 在 p 之后,被 p ~ span 命中(蓝底)

.card p       { }   /* 空格 = 后代:任意深度 */
.card > p     { }   /* > = 子代:只下一层 */
h4 + h4       { }   /* + = 紧邻兄弟:紧跟在后面的那一个 */
p ~ span      { }   /* ~ = 后续兄弟:之后的所有同级 */
A B C > D     { }   /* 可以混用,从右往左读:D 是 C 的子,C 是 B 的后代… */

选择器是从右往左匹配的,所以最右边那一段(关键选择器)越具体,匹配越快。.list-item 好于写成长链 body > div .box ul li a——长链既慢又脆,DOM 一调整就断。

3. 属性选择器全家福

下图给每个链接叠了不同规则:蓝框 = 有 target;浅蓝底 = href 以 https 开头;红底 = 以 .pdf 结尾;粗体 = href 含 docs;绿色虚线 = rel 里有 noopener;加了字距 = class 等于 btn 或以 btn- 开头。

https + target + noopener 本地 PDF 含 docs 的按钮 纯锚点
a[href]           /* 存在该属性 */
a[href="x"]       /* 精确等于(区分大小写) */
a[href="x" i]     /* 忽略大小写 */
a[href^="https"]  /* 前缀 */
a[href$=".pdf"]   /* 后缀 */
a[href*="docs"]   /* 包含 */
a[rel~="noopener"]/* 空格分隔的值列表中包含 */
a[class|="btn"]   /* 等于 btn 或以 "btn-" 开头(历史用于 lang 值) */

4. 结构伪类

:first-child / :last-child        首尾
:nth-child(2n) / :nth-child(even) 偶数;(2n+1)、odd、from-end(2) 都可以
:nth-child(-n+3)                  前 3 个
:only-child                       独子
:empty                            没有子节点也没有文本(注意空白符也算文本)
:not(.is-done)                    排除
:is(h1, h2, h3)                   见第十五章

5. 伪类与伪元素的分界

把鼠标移上来 / 用 Tab 聚焦我 —— :hover、:focus、:focus-visible、:active 描述状态(单冒号);::before、::after、::placeholder、::selection 创建不存在于 DOM 的额外内容(双冒号,第十七章展开)。历史写法单冒号仍兼容,但新代码请统一双冒号。