CSS选择器入门指南

1. 为什么选择器如此重要?

选择器是CSS的核心组成部分,它决定了样式规则应用于哪些HTML元素。一个选择器写得不好,不仅会导致样式难以维护,还可能引起性能问题。

在大型项目中,选择器的质量直接影响代码的可读性和可维护性。我曾经维护过一个老项目,由于选择器写得非常复杂(像.container .content .left .box .title a.active这样的嵌套选择器导致难以维护),最后不得不花费大量时间重构样式表。

2. 基础选择器

2.1 元素选择器

也称为类型选择器,通过HTML元素名称进行选择。

CSS 复制代码
/* 选择所有<p>元素 */
p {
  color: blue;
  line-height: 1.6;
}

2.2 类选择器

通过元素的class属性进行选择,使用点号(.)前缀。

html 复制代码
/* 选择所有class="special"的元素 */
.special {
  background-color: yellow;
  border: 1px solid #ccc;
}

<p class="highlight important">这段文字会受影响</p>
<p class="highlight">这段文字不会受影响</p>
<p class="important">这段文字也不会受影响</p>

/* 选择多个class的元素 */
.highlight.important {
  font-weight: bold;
}

2.3 ID选择器

通过元素的id属性进行选择,使用井号(#)前缀。

CSS 复制代码
/* 选择id="header"的元素 */
#header {
  font-size: 1.5rem;
  margin-bottom: 1rem;
}

最佳实践提示:ID选择器的特异性极高,应谨慎使用。一般来说,只在需要JavaScript频繁操作或非常独特的组件上使用ID。

2.4 通配符选择器

使用星号(*)匹配任意元素。

CSS 复制代码
/* 移除所有元素的默认边距 */
* {
  margin: 0;
  padding: 0;
}
/* 不推荐:性能较差 */
.container * {
  color: red;
}

性能警告:通配符选择器在文档中匹配所有元素,性能较差,应避免过度使用。

2.5 属性选择器

根据元素的属性或属性值进行选择。

html 复制代码
<a href="#" target="_blank"> <!-- 会生效 -->
<a href="#"> <!-- 不会生效 -->
/* 选择有target属性的<a>元素 */
a[target] {
  color: purple;
}

<a href="https://example.com"> <!-- 会生效 -->
<a href="http://example.com"> <!-- 不会生效 -->
/* 选择href属性以"https:"开头的<a>元素 */
a[href^="https:"] {
  font-weight: bold;
}

<div class="alert warning"> <!-- 会生效 -->
<div class="warning-text"> <!-- 会生效 -->
<div class="alert"> <!-- 不会生效 -->
/* 选择class属性包含"warning"的元素 */
[class*="warning"] {
  color: orange;
}

<p data-lang="zh-CN"> <!-- 会生效 -->
<p data-lang="en-US"> <!-- 不会生效 -->
/* 选择data-lang属性为"zh-CN"的元素 */
[data-lang="zh-CN"] {
  font-family: "Microsoft YaHei", sans-serif;
}

3. 组合选择器

3.1 后代选择器

使用空格分隔,匹配指定元素内的所有后代元素。

CSS 复制代码
/* 选择<div>内的所有<p>元素 */
<div>
  <p>这个会变绿色(直接子级)</p>  <!-- ✅ 生效 -->
  
  <section>
    <p>这个也会变绿色(孙子级)</p>  <!-- ✅ 生效 -->
    
    <div>
      <p>这个同样会变绿色(曾孙级)</p>  <!-- ✅ 生效 -->
    </div>
  </section>
</div>
<p>这个不会变绿色(不在div内)</p>  <!-- ❌ 不生效 -->
div p {
  c
}


/* 选择<div class="content">内的所有<span>元素 */
<div class="content">
  <span>字体变大(直接子级)</span>
  <p><span>嵌套的span也变大</span></p>
</div>
div.content span {
  font-size: 1.2rem;
}

3.2 子选择器

使用大于号(>)分隔,仅匹配直接子元素。

CSS 复制代码
<div>
  <p>这个会生效(直接子级)</p>  <!-- ✅ 生效 -->
  
  <section>
    <p>这个不会生效(孙子级)</p>  <!-- ❌ 不生效 -->
  </section>
  
  <div>
    <p>这个也不会生效(嵌套div中的p)</p>  <!-- ✅ 生效 -->
  </div>
</div>

<p>这个不会生效(不在div内)</p>  <!-- ❌ 不生效 -->
/* 选择<div>的直接子元素<p> */
div > p {
  margin-bottom: 1rem;
}
/* 比后代选择器更精确 */
.container > .header {
  padding: 1rem;
}

3.3 相邻兄弟选择器

使用加号(+)分隔,匹配紧接在指定元素后的元素。

CSS 复制代码
<h2>标题1</h2>
<p>这个会生效(紧跟在h2后面)</p>  <!-- ✅ margin-top: 0 -->
<p>这个不会生效(不是紧挨着的)</p>  <!-- ❌ 不受影响 -->

<h2>标题2</h2>
<div>其他内容</div>
<p>这个也不会生效(中间有其他元素隔开)</p>  <!-- ❌ 不受影响 -->

<h2>标题3</h2>
<!-- 这里没有紧跟着的p元素 -->  <!-- ❌ 没有匹配元素 -->

/* 选择紧接在<h2>后的<p>元素 */
h2 + p {
  margin-top: 0;
}
/* 实现常见的卡片设计 */
.card + .card {
  margin-top: 1.5rem;
}

3.4 通用兄弟选择器

使用波浪号(~)分隔,匹配指定元素后的所有兄弟元素。

CSS 复制代码
<div>
  <h2>标题</h2>
  <p>这个会生效(在h2后面)</p>  <!-- ✅ color: gray -->
  <div>其他内容</div>
  <p>这个也会生效(在h2后面)</p>  <!-- ✅ color: gray -->
  <p>这个也会生效</p>  <!-- ✅ color: gray -->
</div>

<p>这个不会生效(不在同一个父元素)</p>  <!-- ❌ 不受影响 -->

<h2>另一个标题</h2>
<!-- 这里没有p元素 -->  <!-- ❌ 没有匹配元素 -->
/* 匹配<h2>后的所有<p>兄弟元素 */
h2 ~ p {
  color: gray;
}
/* 实现选项卡内容切换效果 */
.tab-control ~ .tab-content {
  display: none;
}

4. 结构与伪类选择器

4.1 伪类选择器

匹配元素的特殊状态。

css 复制代码
<CSS>
/* 鼠标悬停 */
a:hover {
  text-decoration: underline;
}
/* 获得焦点 */
input:focus {
  border-color: blue;
  box-shadow: 0 0 5px rgba(0, 0, 255, 0.5);
}
/* 激活状态 */
button:active {
  transform: scale(0.98);
}
/* 链接访问状态 */
a:visited {
  color: purple;
}

4.2 结构伪类

根据元素在文档中的位置匹配元素。

css 复制代码
<CSS>
/* 第一个子元素 */
li:first-child {
  font-weight: bold;
}
/* 最后一个子元素 */
li:last-child {
  border-bottom: none;
}
/* 特定子元素 */
li:nth-child(3) {
  color: red;
}
/* 奇偶行样式 */
tr:nth-child(odd) {
  background-color: #f2f2f2;
}
/* 匹配父元素下唯一的子元素 */
p:only-child {
  font-size: 1.2rem;
}
/* 匹配空元素 */
div:empty {
  display: none;
}

5. 选择器特异性计算

当多个选择器应用于同一元素时,浏览器会根据特异性规则确定应用哪个样式。理解特异性规则对于解决CSS冲突问题至关重要。

5.1 特异性值计算规则

选择器类型 特异性值
行内样式 1000
ID选择器 100
类、属性、伪类 10
元素、伪元素 1
通用选择器、组合符 0

5.2 特异性计算示例

css 复制代码
<CSS>
/* 特异性为1 (元素选择器) */
div {
  color: red;  /* 胜胜 */
}
/* 特异性为10 (类选择器) */
.important {
  color: blue;  /* 胜胜 */
}
/* 特异性为100 (ID选择器) */
#header {
  color: green;  /* 胜胜 */
}

5.3 如何解决特异性冲突

css 复制代码
<CSS>
/* 问题:样式被其他高特异性选择器覆盖 */
.container .content p {
  color: red;  /* 被覆盖 */
}
/* 解决方案1:增加特异性 */
.container .content .article p {
  color: red;  /* 胜胜 */
}
/* 解决方案2:使用!important(不推荐) */
.container .content p {
  color: red !important;  /* 不推荐使用 */
}
/* 解决方案3:重构选择器 */
.article-text {
  color: red;  /* 最佳方案 */
}

6. 实用技巧

6.1 精准定位

sql 复制代码
<CSS>
/* 使用组合选择器减少不必要的特异性 */
.button-primary {
  /* 胜胜胜 */
}
/* 而不是 */
.site-header .nav .button.primary {
  /* 胜胜胜胜 */
}

6.2 BEM方法辅助选择器

sql 复制代码
<CSS>
/* 使用BEM命名规范 */
.block {}
.block__element {}
.block--modifier {}
/* 实际使用 */
.card {}
.card__title {}
.card--featured {}

6.3 使用:not()简化选择器

css 复制代码
<CSS>
/* 传统方法 */
li {
  /* ... */
}
li:last-child {
  border-bottom: none;
}
/* 使用:not()简化 */
li:not(:last-child) {
  border-bottom: 1px solid #ddd;
}

7. 性能考虑

选择器的性能影响在大型项目中尤为明显。以下是优化选择器性能的一些关键点:

  1. 避免过长的选择器链:深度嵌套选择器会增加计算时间。
  2. 减少通用选择器的使用*选择器会匹配所有元素,性能较差。
  3. 限制使用标签选择器的数量:在类选择器前使用标签选择器增加了特异性,但没有提高性能。
  4. 避免过度使用后代选择器:后代选择器会遍历整个DOM树查找匹配。
css 复制代码
<CSS>
/* 低效 */
.container div p span a {
  /* 样式 */
}
/* 高效 */
.link {
  /* 样式 */
}
相关推荐
子兮曰3 小时前
现代滚动技术深度解析:scrollTo与behavior属性的应用与原理
前端·javascript·浏览器
然我3 小时前
JavaScript 的 this 到底是个啥?从调用逻辑到手写实现,彻底搞懂绑定机制
前端·javascript·面试
舒一笑3 小时前
Mac环境安装Nginx指南实录
前端·nginx·程序员
林希_Rachel_傻希希3 小时前
别再写 c=3 了!window 对象的隐藏规则
前端·javascript
_AaronWong3 小时前
Vue页面返回滚动位置恢复:keep-alive滚动记忆
前端·vue-router
子兮曰3 小时前
深度解析Proxy与目标对象(definiteObject):原理、特性与10个实战案例
前端·javascript·node.js
克里斯蒂亚L3 小时前
禁止打开多个浏览器标签页访问相同地址的页面:Cookie + SessionStorage
前端
倔强青铜三4 小时前
苦练Python第48天:类的私有变量“防身术”,把秘密藏进类里!
人工智能·python·面试
倔强青铜三4 小时前
苦练Python第47天:一文吃透继承与多继承,MRO教你不再踩坑
人工智能·python·面试