Skip to content

CSS 选择器基础

CSS 选择器是样式与 HTML 元素之间的桥梁。写好选择器,意味着你能精准地控制页面上的每一个元素。这篇文章将从最基础的选择器开始,逐步深入到组合选择器和优先级计算。

基础选择器#

通用选择器#

通用选择器 * 匹配页面上的所有元素:

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

🔶 通用选择器的性能开销较大,尽量避免单独使用。上面的 CSS Reset 是它最常见的用途。

元素选择器#

元素选择器(也叫类型选择器)通过标签名匹配元素:

p {
line-height: 1.6;
}
h1 {
font-size: 2rem;
}
a {
color: #3b82f6;
text-decoration: none;
}

类选择器#

类选择器通过 class 属性匹配元素,是日常开发中使用最频繁的选择器:

.button {
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
}
.button-primary {
background-color: #3b82f6;
color: white;
}
.button-secondary {
background-color: #e5e7eb;
color: #374151;
}
<button class="button button-primary">主要按钮</button>
<button class="button button-secondary">次要按钮</button>

一个元素可以拥有多个类名,用空格分隔。这种方式非常适合组合样式。

ID 选择器#

ID 选择器通过 id 属性匹配元素:

#header {
position: fixed;
top: 0;
width: 100%;
}
#main-content {
margin-top: 60px;
}

🔶 ID 在页面中应该是唯一的。由于 ID 选择器的优先级很高,过度使用会导致样式难以覆盖,现代开发中更推荐使用类选择器。

属性选择器#

属性选择器让你可以根据元素的属性及其值来匹配元素。

基本属性选择器#

/* 匹配所有带 disabled 属性的元素 */
[disabled] {
opacity: 0.5;
cursor: not-allowed;
}
/* 匹配所有带 type 属性的 input 元素 */
input[type] {
border: 1px solid #d1d5db;
}

精确匹配#

/* type 值完全等于 "password" */
input[type='password'] {
font-family: monospace;
}
/* href 值完全等于指定 URL */
a[href="https://example.com"]
{
color: green;
}

模糊匹配#

属性选择器支持多种模糊匹配模式:

/* 以 "https" 开头 */
a[href^='https'] {
padding-left: 20px;
background: url('lock.svg') no-repeat left center;
}
/* 以 ".pdf" 结尾 */
a[href$='.pdf'] {
padding-right: 20px;
background: url('pdf.svg') no-repeat right center;
}
/* 包含 "example" */
a[href*='example'] {
color: orange;
}
/* 包含完整单词 "warning"(空格分隔) */
[class~='warning'] {
border-left: 4px solid #f59e0b;
}
/* 值为 "zh" 或以 "zh-" 开头 */
[lang|='zh'] {
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
}

大小写不敏感匹配#

在属性选择器末尾添加 i 可以忽略大小写:

a[href$='.PDF' i] {
/* 匹配 .pdf、.PDF、.Pdf 等 */
}

组合选择器#

组合选择器用于描述元素之间的关系。

后代选择器#

后代选择器(空格)匹配所有后代元素,不论嵌套多深:

article p {
margin-bottom: 1rem;
}
.card .title {
font-weight: bold;
}

子代选择器#

子代选择器(>)只匹配直接子元素:

/* 只匹配 nav 的直接子元素 ul */
nav > ul {
display: flex;
list-style: none;
}
/* 只匹配一级列表项 */
ul > li {
padding: 0.5rem;
}

🙋 什么时候用子代选择器?当你想避免样式影响到嵌套结构时:

/* 避免影响嵌套的下拉菜单 */
.menu > li {
display: inline-block;
}
/* 如果用后代选择器,嵌套菜单的 li 也会变成 inline-block */
.menu li {
display: inline-block; /* 可能不是你想要的 */
}

相邻兄弟选择器#

相邻兄弟选择器(+)匹配紧跟在指定元素后的元素:

/* h2 后面紧跟的 p */
h2 + p {
font-size: 1.1rem;
color: #6b7280;
}
/* 表单标签后紧跟的输入框 */
label + input {
margin-left: 0.5rem;
}

通用兄弟选择器#

通用兄弟选择器(~)匹配后面的所有兄弟元素:

/* h2 后面的所有 p(同级) */
h2 ~ p {
text-indent: 2em;
}

对比:

<article>
<h2>标题</h2>
<p>第一段 - h2 + p 和 h2 ~ p 都能匹配</p>
<p>第二段 - 只有 h2 ~ p 能匹配</p>
<div>
<p>嵌套段落 - 都无法匹配(不是兄弟元素)</p>
</div>
</article>

选择器列表#

使用逗号分隔多个选择器,可以对它们应用相同的样式:

h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'Georgia', serif;
line-height: 1.2;
}
button,
input[type='submit'],
input[type='button'] {
cursor: pointer;
}

🔶 选择器列表中如果有一个无效,整个规则都会失效(不过现代浏览器对 :is():where() 中的无效选择器有容错处理)。

优先级计算#

🎯 理解优先级是掌握 CSS 的关键。当多个规则作用于同一元素时,浏览器根据优先级决定使用哪个。

优先级权重#

优先级用三个数字表示:(ID数量)-(类/属性/伪类数量)-(元素/伪元素数量)

#myElement input.myClass {
color: red;
} /* 1-1-1 */
input[type='password']:required {
color: blue;
} /* 0-2-1 */
html body main input {
color: green;
} /* 0-0-4 */

比较规则是从左到右,左边的列权重更高:

特殊情况#

通用选择器 * 不增加优先级

* {
} /* 0-0-0 */
div {
} /* 0-0-1 */

!important 优先级最高(但应尽量避免使用):

p {
color: red !important; /* 胜过任何非 !important 规则 */
}

内联样式优先级高于选择器

<p style="color: blue;">内联样式优先</p>

降低 ID 选择器的优先级#

如果需要匹配 ID 但不想增加优先级,可以使用属性选择器:

#myContent h1 {
color: green;
} /* 1-0-1 */
[id='myContent'] h1 {
color: yellow;
} /* 0-1-1 - 更容易被覆盖 */
:where(#myContent) h1 {
color: blue;
} /* 0-0-1 - :where() 不增加优先级 */

实战案例#

导航菜单样式#

/* 导航容器 */
.nav {
display: flex;
gap: 1rem;
padding: 1rem;
background: #1f2937;
}
/* 一级菜单项 */
.nav > a {
color: #d1d5db;
text-decoration: none;
padding: 0.5rem 1rem;
border-radius: 4px;
transition: background-color 0.2s;
}
/* 悬停效果 */
.nav > a:hover {
background-color: #374151;
color: white;
}
/* 当前页面 */
.nav > a[aria-current='page'] {
background-color: #3b82f6;
color: white;
}
<nav class="nav">
<a href="/" aria-current="page">首页</a>
<a href="/about">关于</a>
<a href="/blog">博客</a>
<a href="/contact">联系</a>
</nav>

表单验证样式#

/* 输入框基础样式 */
.form-input {
width: 100%;
padding: 0.75rem 1rem;
border: 1px solid #d1d5db;
border-radius: 6px;
transition:
border-color 0.2s,
box-shadow 0.2s;
}
/* 聚焦状态 */
.form-input:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
/* 验证通过 */
.form-input:valid {
border-color: #10b981;
}
/* 验证失败 */
.form-input:invalid:not(:placeholder-shown) {
border-color: #ef4444;
}
/* 禁用状态 */
.form-input:disabled {
background-color: #f3f4f6;
cursor: not-allowed;
}
/* 标签与输入框的间距 */
label + .form-input {
margin-top: 0.25rem;
}

文章排版#

article {
max-width: 65ch;
margin: 0 auto;
line-height: 1.75;
}
/* 标题层级 */
article h2 {
margin-top: 2rem;
margin-bottom: 1rem;
font-size: 1.5rem;
}
article h3 {
margin-top: 1.5rem;
margin-bottom: 0.75rem;
font-size: 1.25rem;
}
/* 段落间距 */
article p + p {
margin-top: 1rem;
}
/* 标题后的首段不需要缩进 */
article h2 + p,
article h3 + p {
margin-top: 0.5rem;
}
/* 列表样式 */
article ul,
article ol {
padding-left: 1.5rem;
margin: 1rem 0;
}
article li + li {
margin-top: 0.5rem;
}
/* 外部链接标记 */
article a[href^='http']:not([href*='mysite.com'])::after {
content: '';
font-size: 0.75em;
}

常见问题#

🤔 为什么我的样式不生效?

  1. 检查选择器是否写对(拼写、大小写)
  2. 检查优先级是否被其他规则覆盖
  3. 打开浏览器开发者工具,查看样式是否被划掉

🤔 class 和 id 该用哪个?

优先使用 class。ID 适合作为 JavaScript 钩子或页面锚点,不建议用于样式。

🤔 选择器越精确越好吗?

不是。过于精确的选择器会增加优先级,导致后续覆盖困难。保持选择器简洁,通常 1-2 层嵌套就够了。


选择器是 CSS 的基础,掌握它们能让你更灵活地控制样式。下一篇文章我们将深入 CSS 盒模型,理解每个元素如何占据空间。