第一部分:CSS 选择器 (Selector)
CSS 选择器的作用就像一个“寻址系统”,它告诉浏览器:“请找到网页上所有符合这些条件的 HTML 元素,然后把这些样式应用给它们。”
下面是常用选择器的分类,从基础到高级:
1. 基础选择器 (Basic Selectors)
| 选择器类型 | 语法 | 示例 | 描述 |
|---|---|---|---|
| 元素选择器 (Element) | element | p { color: blue; } | 选择所有 标签。 |
| 类选择器 (Class) | .classname | .important { font-weight: bold; } | 选择所有 class="important" 的元素。 |
| ID 选择器 (ID) | #idname | #header { background: #eee; } | 选择 id="header" 的那个唯一元素。 |
| 属性选择器 (Attribute) | [attribute] | [type="submit"] { cursor: pointer; } | 选择所有 type 属性为 submit 的元素。 |
| 通用选择器 (Universal) | * | * { box-sizing: border-box; } | 选择页面上所有的元素。 |
2. 组合选择器 (Combinators)
组合选择器通过元素之间的关系来定位它们。
| 组合方式 | 语法 | 示例 | 描述 |
|---|---|---|---|
| 后代选择器 | A B | div p { color: gray; } | 选择 元素内部所有的 元素。 |
| 子代选择器 | A > B | ul > li { list-style: none; } | 选择
|
| 相邻兄弟选择器 | A + B | h2 + p { margin-top: 0; } | 选择紧跟在 元素后面的那一个元素。 |
| 通用兄弟选择器 | A ~ B | h2 ~ p { text-indent: 2em; } | 选择在 元素后面的所有同级元素。 |
3. 分组选择器 (Grouping Selector)
| 语法 | 示例 | 描述 |
|---|---|---|
| A, B | h1, h2, .title { font-family: 'Arial'; } | 同时选择所有 、和带有 .title 类的元素,为它们应用相同的样式。 |
4. 伪类选择器 (Pseudo-classes)
伪类用于选择处于特定状态或位置的元素。它以一个冒号 : 开头。
-
动态状态伪类:
- :hover:鼠标悬停在元素上时。
- :active:元素被激活时(如点击鼠标)。
- :focus:元素获得焦点时(如输入框被选中)。
-
结构性伪类:
- :first-child:作为其父元素的第一个子元素。
- :last-child:作为其父元素的最后一个子元素。
- :nth-child(n):选择第 n 个子元素。例如 li:nth-child(2) 选择第二个
- ,li:nth-child(odd) 选择奇数位的
- 。
- :not(selector):选择不匹配括号内选择器的元素。例如 p:not(.fancy) 选择所有不含 .fancy 类的
元素。
5. 伪元素选择器 (Pseudo-elements)
伪元素用于为元素的特定部分设置样式,它像一个“虚拟”的元素。它以两个冒号 :: 开头(为了与伪类区分,但单冒号也能兼容旧浏览器)。
- ::before:在元素内容之前插入一个虚拟元素。
- ::after:在元素内容之后插入一个虚拟元素。
- ::first-line:选择元素的第一行文本。
- ::first-letter:选择元素的第一个字母。
- ::selection:选择用户用鼠标高亮选中的部分。
第二部分:选择器优先级 (Specificity)
当多个 CSS 规则都指向同一个元素时,浏览器需要一套规则来决定哪个样式最终生效。这套规则就是“优先级”。
可以把优先级想象成一个“分数”,分数越高的规则,其样式就会覆盖分数低的。
优先级计算规则
优先级的计算可以总结为一个四位数的“计分板”: (a, b, c, d)
-
a: 行内样式 (Inline Styles)
- 如果样式是写在 HTML 元素的 style 属性里,a 就计 1 分。
- 例如:
-
b: ID 选择器
- 选择器中每出现一个 ID 选择器 (#id),b 就加 1 分。
-
c: 类、属性、伪类选择器
- 选择器中每出现一个类选择器 (.class)、属性选择器 ([type="text"]) 或伪类 (:hover),c 就加 1 分。
-
d: 元素、伪元素选择器
- 选择器中每出现一个元素选择器 (div) 或伪元素 (::before),d 就加 1 分。
注意: 通用选择器 * 和组合器 (>, +, ~, ' ') 不增加任何分数。
比较规则
- 从左到右,逐位比较。 先比较 a,如果 a 大,则胜出,后面的就不比了。
- 如果 a 相同,再比较 b,b 大的胜出。
- 以此类推,直到 d。
- 这个分数不是十进制的,也就是说,c 的值再大(比如 11 个 class)也无法超越 b 的 1 个 ID。即 (0,1,0,0) 永远大于 (0,0,11,0)。
示例
假设我们有以下 HTML 和 CSS:
codeHtml
<div id="nav">
<ul class="menu">
<li><a href="#" class="active">Home</a></li>
</ul>
</div>
codeCSS
/* 规则 1 */
#nav .menu li a { color: blue; }
/* 规则 2 */
#nav a.active { color: red; }
/* 规则 3 */
a { color: green; }
我们来计算 <a> 标签的颜色优先级:
-
规则 1: #nav .menu li a
- a (行内): 0
- b (ID): 1 (#nav)
- c (类): 1 (.menu)
- d (元素): 3 (li, a, div 是隐式的但常被省略) -> 严格来说是 2 (li, a)
- 分数: (0, 1, 1, 2)
-
规则 2: #nav a.active
- a (行内): 0
- b (ID): 1 (#nav)
- c (类): 1 (.active)
- d (元素): 1 (a)
- 分数: (0, 1, 1, 1)
-
规则 3: a
- a (行内): 0
- b (ID): 0
- c (类): 0
- d (元素): 1 (a)
- 分数: (0, 0, 0, 1)
比较结果:
- 规则 1 和规则 2 的 b 和 c 位都相同(都是 1)。
- 比较 d 位,规则 1 的 d 是 2,规则 2 的 d 是 1。
- 所以,规则 1 的优先级更高。最终
<a>标签的颜色会是 blue。
特殊规则
-
!important
- 这是一个“王炸”。任何带有 !important 的样式声明都会覆盖其他所有声明,包括行内样式。
- p { color: purple !important; }
- 强烈建议:除非万不得已(例如需要覆盖第三方库的行内样式),否则不要使用 !important。它会破坏 CSS 的自然层叠规则,让调试和维护变得非常困难。
-
源次序 (Source Order)
- 如果两个规则的优先级完全相同,那么在样式表中后出现的规则会覆盖先出现的规则。
codeCSS
p { color: blue; } /* 分数 (0,0,0,1) */ p { color: red; } /* 分数 (0,0,0,1) - 这个生效,因为在后面 */
总结与最佳实践
- 优先级层级:
!important > 行内样式 > ID > 类/属性/伪类 > 元素/伪元素 > 通用选择器。 - 尽量使用类选择器:这是最常用、最灵活的方式。ID 的权重太高,不利于复用和覆盖。
- 保持选择器简洁:不要写过度限定的选择器,如 body #main .content .article h2。简单的 .article-title 既高效又易于维护。
- 理解但不依赖优先级:好的 CSS 结构应该利用层叠(Cascade)的特性,而不是通过复杂的优先级计算来“斗争”。
- 避免 !important:把它当作最后的、迫不得已的手段。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>CSS 选择器示例</title>
<style>
/* CSS 规则将写在这里 */
</style>
</head>
<style>
/* 1.1 元素选择器 (Element Selector) */
/* 选择所有的 <p> 元素,将它们的行高设置为 1.5 */
p {
line-height: 1.5;
}
/* 1.2 类选择器 (Class Selector) */
/* 选择所有 class="nav-link" 的元素,去掉下划线 */
.nav-link {
text-decoration: none;
color: #333;
}
/* 1.3 ID 选择器 (ID Selector) */
/* 选择 id="main-header" 的元素,添加一个下边框 */
#main-header {
border-bottom: 2px solid #f0f0f0;
padding-bottom: 10px;
}
/* 1.4 属性选择器 (Attribute Selector) */
/* 选择所有带有 target="_blank" 属性的 <a> 元素,在后面添加一个图标 */
a[target="_blank"]::after {
content: " ↗"; /* 添加一个向外的箭头符号 */
}
/* 选择所有 type="text" 的 <input> 元素 */
input[type="text"] {
border: 1px solid #ccc;
padding: 5px;
}
/* 1.5 通用选择器 (Universal Selector) */
/* 选择所有元素,设置一个更直观的盒模型(非常常见的做法) */
* {
box-sizing: border-box;
font-family: sans-serif;
}
/* 2.1 后代选择器 (Descendant Selector) */
/* 选择 .article-content 内部的 所有 p 元素 */
.article-content p {
color: #555;
}
/* 2.2 子代选择器 (Child Selector) */
/* 只选择 nav 元素的 直接子元素 ul */
nav > ul {
list-style: none; /* 去掉列表的点 */
padding-left: 0;
}
/* 2.3 相邻兄弟选择器 (Adjacent Sibling Selector) */
/* 选择 紧跟在 h2 后面的那一个 p 元素,并改变其字体样式 */
h2 + p {
font-style: italic;
color: #888;
}
/* 2.4 通用兄弟选择器 (General Sibling Selector) */
/* 选择 h2 元素后面的 所有同级 p 元素,并增加左边距 */
h2 ~ p {
margin-left: 20px;
}
/* 同时选择 h1, h2, 和 button 元素,设置相同的字体粗细 */
h1,
h2,
button {
font-weight: bold;
color: #2c3e50;
}
/* 4.1 动态状态伪类 */
/* 当鼠标悬停在 .nav-link 上时,改变颜色 */
.nav-link:hover {
color: #007bff;
}
/* 当 .nav-link.active (即首页链接) 时,显示为粗体 */
.nav-link.active {
font-weight: bold;
}
/* 当输入框获得焦点时,边框变色 */
input:focus {
outline: none;
border-color: #007bff;
}
/* 选择被禁用的 button */
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
/* 4.2 结构性伪类 */
/* 选择列表中的第一个 li 元素 */
.item:first-child {
color: green;
}
/* 选择列表中的第偶数个 li 元素,实现斑马条纹效果 */
.item:nth-child(even) {
background-color: #f9f9f9;
}
/* 选择所有 p 元素中,不包含 .intro 类的元素 */
p:not(.intro) {
border-left: 3px solid #eee;
padding-left: 10px;
}
/* 5.1 ::before 和 ::after */
/* 在 class="special-item" 的 li 元素内容前添加一个星号 */
.special-item::before {
content: "★ ";
color: gold;
}
/* 在整个 .article-content 区域的末尾添加一条分割线 */
.article-content::after {
content: "--- 阅读结束 ---";
display: block;
text-align: center;
margin-top: 20px;
color: #aaa;
}
/* 5.2 ::first-letter 和 ::first-line */
/* 选择 .intro 段落的第一个字母,实现首字下沉效果 */
.intro::first-letter {
font-size: 2em;
font-weight: bold;
float: left;
margin-right: 5px;
line-height: 1;
}
/* 选择 .intro 段落的第一行,改变其颜色 */
.intro::first-line {
color: #3498db;
}
/* 5.3 ::selection */
/* 当用户用鼠标选中页面上的文本时,改变背景和字体颜色 */
::selection {
background-color: #007bff;
color: white;
}
</style>
<body>
<header id="main-header">
<h1>网站标题</h1>
<nav>
<ul>
<li><a href="#home" class="nav-link active">首页</a></li>
<li><a href="#about" class="nav-link">关于</a></li>
<li>
<a href="https://example.com" class="nav-link" target="_blank"
>外部链接</a
>
</li>
</ul>
</nav>
</header>
<main class="article-content">
<h2>文章副标题</h2>
<p class="intro">这是文章的介绍段落。</p>
<p>这是文章的第二个段落,用来演示通用兄弟选择器。</p>
<div>
<p>这是一个在 div 内部的段落。</p>
</div>
<ul>
<li class="item">列表项 1</li>
<li class="item special-item">列表项 2 (特殊)</li>
<li class="item">列表项 3</li>
<li class="item">列表项 4</li>
</ul>
</main>
<form id="contact-form">
<input type="text" placeholder="你的名字" />
<button type="submit" disabled>提交 (禁用)</button>
</form>
</body>
</html>