详细讲解css的选择器

58 阅读8分钟

第一部分:CSS 选择器 (Selector)

CSS 选择器的作用就像一个“寻址系统”,它告诉浏览器:“请找到网页上所有符合这些条件的 HTML 元素,然后把这些样式应用给它们。”

下面是常用选择器的分类,从基础到高级:

1. 基础选择器 (Basic Selectors)
选择器类型语法示例描述
元素选择器 (Element)elementp { 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 Bdiv p { color: gray; }选择 
 元素内部所有的 

 元素。

子代选择器A > Bul > li { list-style: none; }选择 
     元素的直接子元素 
相邻兄弟选择器A + Bh2 + p { margin-top: 0; }选择紧跟在 

 元素后面的那一个 

 元素。

通用兄弟选择器A ~ Bh2 ~ p { text-indent: 2em; }选择在 

 元素后面的所有同级 

 元素。

3. 分组选择器 (Grouping Selector)
语法示例描述
A, Bh1, 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)

  1. a: 行内样式 (Inline Styles)

    • 如果样式是写在 HTML 元素的 style 属性里,a 就计 1 分。
    • 例如:

  2. b: ID 选择器

    • 选择器中每出现一个 ID 选择器 (#id),b 就加 1 分。
  3. c: 类、属性、伪类选择器

    • 选择器中每出现一个类选择器 (.class)、属性选择器 ([type="text"]) 或伪类 (:hover),c 就加 1 分。
  4. 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. 规则 1 和规则 2 的 b 和 c 位都相同(都是 1)。
  2. 比较 d 位,规则 1 的 d 是 2,规则 2 的 d 是 1。
  3. 所以,规则 1 的优先级更高。最终 <a> 标签的颜色会是 blue
特殊规则
  1. !important

    • 这是一个“王炸”。任何带有 !important 的样式声明都会覆盖其他所有声明,包括行内样式
    • p { color: purple !important; }
    • 强烈建议:除非万不得已(例如需要覆盖第三方库的行内样式),否则不要使用 !important。它会破坏 CSS 的自然层叠规则,让调试和维护变得非常困难。
  2. 源次序 (Source Order)

    • 如果两个规则的优先级完全相同,那么在样式表中后出现的规则会覆盖先出现的规则。

    codeCSS

    p { color: blue; }  /* 分数 (0,0,0,1) */
    p { color: red; }   /* 分数 (0,0,0,1) - 这个生效,因为在后面 */
    

总结与最佳实践

  1. 优先级层级!important > 行内样式 > ID > 类/属性/伪类 > 元素/伪元素 > 通用选择器。
  2. 尽量使用类选择器:这是最常用、最灵活的方式。ID 的权重太高,不利于复用和覆盖。
  3. 保持选择器简洁:不要写过度限定的选择器,如 body #main .content .article h2。简单的 .article-title 既高效又易于维护。
  4. 理解但不依赖优先级:好的 CSS 结构应该利用层叠(Cascade)的特性,而不是通过复杂的优先级计算来“斗争”。
  5. 避免 !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>