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 */比较规则是从左到右,左边的列权重更高:
1-1-1>0-2-1:ID 列 1 > 0,红色胜出0-2-1>0-0-4:类列 2 > 0,蓝色胜出
特殊情况#
通用选择器 * 不增加优先级:
* {} /* 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;}常见问题#
🤔 为什么我的样式不生效?
- 检查选择器是否写对(拼写、大小写)
- 检查优先级是否被其他规则覆盖
- 打开浏览器开发者工具,查看样式是否被划掉
🤔 class 和 id 该用哪个?
优先使用 class。ID 适合作为 JavaScript 钩子或页面锚点,不建议用于样式。
🤔 选择器越精确越好吗?
不是。过于精确的选择器会增加优先级,导致后续覆盖困难。保持选择器简洁,通常 1-2 层嵌套就够了。
选择器是 CSS 的基础,掌握它们能让你更灵活地控制样式。下一篇文章我们将深入 CSS 盒模型,理解每个元素如何占据空间。