Appearance
03|CSS 选择器与优先级
HTML 搭好骨架后,需要 CSS 来控制外观。CSS 的核心问题是:选谁,然后改成什么样。选择器负责"选谁",声明块负责"改成什么样"。这篇先把选择器讲清楚——选不对元素,后面的样式声明再正确也落不到目标上。
一、基础选择器
元素选择器
直接写标签名,选中页面中所有该标签:
css
p {
color: #333;
}
h1 {
font-size: 24px;
}上面的规则让所有 p 标签文字变深灰,所有 h1 标签字号 24 像素。元素选择器覆盖面太广,通常和其他选择器配合使用。
类选择器
用 . 开头,选中带有对应 class 属性的元素。这是日常开发最常用的选择器:
html
<p class="intro">这是介绍文字。</p>
<p>这是普通段落。</p>css
.intro {
color: #666;
font-style: italic;
}只有带有 class="intro" 的段落会应用 italic 样式。一个元素可以有多个类,用空格分隔:
html
<div class="card highlight">...</div>css
.card {
border: 1px solid #ddd;
padding: 16px;
}
.highlight {
background-color: #fffbe6;
}这个 div 同时具有卡片边框和高亮背景。类的命名用小写、连字符分隔(article-title,不是 articleTitle 或 article_title),这是 CSS 社区的普遍约定。
ID 选择器
用 # 开头,选中带有对应 id 属性的元素:
html
<div id="header">...</div>css
#header {
background-color: #f5f5f5;
}同一页面中,id 必须唯一。CSS 层面不强制唯一(重复 id 时选择器仍能匹配),但 JavaScript 的 getElementById 只会返回第一个,且 id 作为页面锚点使用时也必须唯一。ID 选择器的优先级很高,过度使用会导致后续样式难以覆盖。
通用选择器
* 选中所有元素,通常用于重置默认样式:
css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}通用选择器的优先级最低,会被任何其他选择器覆盖。
二、组合选择器
后代选择器
用空格分隔,选中某元素内部的所有目标元素(无论嵌套多深):
css
.article p {
line-height: 1.8;
}选中所有位于 .article 元素内部的 p 标签,不管中间隔了多少层。
子代选择器
用 > 分隔,只选中直接子元素:
css
.nav > li {
display: inline-block;
}只选中 .nav 的直接 li 子元素。如果 li 内部还有嵌套的 li,不会被选中。
相邻兄弟选择器
用 + 分隔,选中紧接在指定元素之后的第一个兄弟元素:
css
h2 + p {
margin-top: 0;
}选中紧跟在 h2 后面的第一个 p。如果 h2 和 p 之间有其他元素,则不生效。
通用兄弟选择器
用 ~ 分隔,选中指定元素之后的所有兄弟元素:
css
h2 ~ p {
color: #666;
}选中 h2 之后所有同级的 p,不要求紧邻。
三、伪类
伪类选中元素的特定状态或位置,以 : 开头:
状态伪类
css
/* 鼠标悬停 */
a:hover {
text-decoration: underline;
}
/* 获得焦点(键盘 Tab 或点击输入框) */
input:focus {
border-color: #1890ff;
outline: none;
}
/* 已访问的链接 */
a:visited {
color: #800080;
}位置伪类
css
/* 第一个子元素 */
li:first-child {
border-top: none;
}
/* 最后一个子元素 */
li:last-child {
border-bottom: none;
}
/* 第 n 个子元素 */
li:nth-child(2) {
background-color: #f0f0f0;
}
/* 奇数项 */
li:nth-child(odd) {
background-color: #fafafa;
}
/* 偶数项 */
li:nth-child(even) {
background-color: #fff;
}nth-child 的参数可以是数字、关键字(odd/even)或公式(2n+1 表示奇数项,3n 表示每三项)。
否定伪类
css
/* 选中不是 .disabled 的按钮 */
button:not(.disabled) {
cursor: pointer;
}四、伪元素
伪元素创建不存在于 HTML 中的元素,以 :: 开头:
css
/* 在元素内容前插入 */
.quote::before {
content: """;
color: #999;
}
/* 在元素内容后插入 */
.quote::after {
content: """;
color: #999;
}
/* 第一行 */
p::first-line {
font-weight: bold;
}
/* 选中的文字 */
::selection {
background-color: #1890ff;
color: #fff;
}::before 和 ::after 必须配合 content 属性使用,即使 content 为空字符串。插入的内容在 DOM 中不可见,不属于 HTML 结构,但会渲染在页面上。
CSS2 中伪元素用一个冒号(:before),CSS3 规范改为双冒号(::before)以区分伪类。现代浏览器两者都支持,但推荐使用双冒号写法。
五、优先级(特指度)
当多个选择器对同一个元素声明了冲突的样式时,浏览器按优先级决定应用哪一条。优先级由三个数字组成 (a, b, c):
| 分量 | 计数规则 |
|---|---|
a | ID 选择器的数量 |
b | 类选择器、伪类、属性选择器的数量 |
c | 元素选择器、伪元素的数量 |
比较时先比 a,a 相同再比 b,b 相同再比 c。
css
/* (0, 0, 1) - 一个元素 */
p { color: black; }
/* (0, 1, 0) - 一个类 */
.text { color: red; }
/* (0, 1, 1) - 一个类 + 一个元素 */
p.text { color: blue; }
/* (1, 0, 0) - 一个 ID */
#intro { color: green; }对同一个段落 <p class="text" id="intro">,最终颜色是绿色——ID 选择器的优先级最高。
内联样式
写在元素 style 属性中的样式优先级高于所有选择器:
html
<p style="color: purple;">这段文字是紫色</p>内联样式的特指度记为 (1, 0, 0, 0),比 ID 选择器的 (1, 0, 0) 更高。
!important
css
p {
color: red !important;
}!important 覆盖一切优先级计算,包括内联样式。除非处理第三方库的样式覆盖,否则不要使用 !important。一旦滥用,样式追踪会变得极其困难。
优先级相同的情况
如果两个选择器的特指度完全相同,后写的规则生效:
css
.text { color: red; }
.text { color: blue; } /* 这条生效,段落为蓝色 */六、继承
部分 CSS 属性会自动从父元素继承到子元素:
| 可继承属性 | 不可继承属性 |
|---|---|
color | width、height |
font-family、font-size | margin、padding |
line-height | border、background |
text-align | display、position |
css
body {
color: #333;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}页面中所有文字都会继承 body 的字体和颜色,不需要给每个元素重复声明。不可继承的属性(如 margin)需要显式设置。
可以用 inherit 关键字强制继承:
css
input {
font-family: inherit; /* 强制继承父元素的字体 */
}七、常见错误
过度使用 ID 选择器
css
/* 不建议:ID 优先级过高,后续难以覆盖 */
#sidebar .menu .item a { color: #333; }
/* 建议:用类控制,保持优先级扁平 */
.sidebar-menu-link { color: #333; }选择器过长
css
/* 不建议:维护困难,性能差 */
.page-wrapper .content-area .article-list .article-item .title {
font-size: 18px;
}
/* 建议:给目标元素直接加类 */
.article-title { font-size: 18px; }选择器越长,浏览器匹配时的工作量越大,且一旦 HTML 结构变动(中间某层 div 改名或增加),CSS 就会失效。
用 !important 解决优先级问题
css
/* 错误:引入 important 后,后续所有覆盖都需要 important */
.button { color: red !important; }
/* 正确:提升原选择器的优先级 */
.button.primary { color: blue; }