首页
/ freeCodeCamp Basic-CSS 实战:用 id 选择器覆盖 Class 声明,理解 CSS 优先级机制

freeCodeCamp Basic-CSS 实战:用 id 选择器覆盖 Class 声明,理解 CSS 优先级机制

2026-09-06 17:18:19作者:房伟宁

本篇基于 freeCodeCamp 课程中 basic-css 模块的实战练习 Override Class Declarations by Styling ID Attributes,讲解当同一个元素同时命中多个 CSS 声明时的冲突裁决规则:为什么"后声明的 class"会覆盖"先声明的 class",以及如何通过为元素添加 id 属性并编写 #id 选择器,无条件地压过所有 class 级声明。读完后你将掌握 id 选择器的写法、class 声明顺序与 HTML 中使用顺序的区别,并能用计算样式(getComputedStyle)验证覆盖结果。

前置背景:这条课程线的演进脉络

该练习位于课程文件 curriculum/structure/superblocks/responsive-web-design.json 所定义的 Responsive Web Design 超级块下的 basic-css 区块,是其中"样式优先级"三连击的中间一环。从 challengeOrder 的顺序 可以看到这条知识链:

  1. Prioritize One Style Over Another源文件):创建 .pink-text class 并应用到 h1,证明 class 声明可以覆盖 body 元素继承下来的 color: green
  2. Override Styles in Subsequent CSS源文件):在 .pink-text 之后再声明 .blue-text,同时把两个 class 加到同一个 h1 上,证明声明顺序靠后者获胜,而与 HTML 中 class 的书写顺序无关。
  3. 本篇:Override Class Declarations by Styling ID Attributes:进一步用 #orange-text id 声明覆盖上述两个 class 的声明。

本篇练习结束后,课程还会继续讲解用内联 style 属性(Override Class Declarations with Inline Styles)和 !importantOverride All Other Styles by using Important)覆盖声明,共同构成完整的优先级阶梯。

而 id 选择器本身并非本篇首次出现——在更早的 Use an id Attribute to Style an Element 练习中已经建立了两个关键认知:id 不可复用、只应用于一个元素;id 的优先级(specificity)高于 class,两者冲突时 id 的样式胜出。本篇正是在此基础上做的实战验证。

核心概念回顾:声明顺序决定 class 冲突的赢家

练习文档开头的 description 部分首先回顾上一节的结论:浏览器按 CSS 声明在 <style> 元素中的书写顺序自上而下读取,冲突时采用最后声明的那条。这里有一个容易被忽视的细节:

即使我们在 h1 元素的 class 列表中把 blue-text 写在 pink-text 前面,浏览器看的依然是声明顺序,而不是它们被使用的顺序!

这一点与上一节练习中的 Note 呼应:"It doesn't matter which order the classes are listed in the HTML element. However, the order of the class declarations in the <style> section is what is important."

练习任务:给 h1 添加 id 并编写 id 声明

本篇练习的具体目标,是把 h1 的文字变成橙色,手段是绕开 class 声明顺序——给元素一个 id,然后为这个 id 写 CSS 声明。文档给出的操作步骤如下:

  1. h1 元素添加 id 属性,值为 orange-text。id 属性在 HTML 中的写法形如:

    <h1 id="orange-text">
    
  2. 保留 h1 上原有的 blue-textpink-text 两个 class,不要移除。

  3. style 元素中为 orange-text 这个 id 创建 CSS 声明。id 选择器的语法是在 id 名前加 #,文档给出的示例:

    #brown-text {
      color: brown;
    }
    

    按同样格式,你需要写的是:

    #orange-text {
      color: orange;
    }
    

文档特别强调了一条关键规则,也是本篇的题眼:

Note: 无论你把这条 CSS 声明写在 .pink-text class 的上面还是下面,都没有关系——因为 id 属性声明永远优先(the id attribute will always take precedence)。

这意味着 id 声明的胜负与声明顺序解耦了,这与上一节"后声明者胜"的 class 规则形成鲜明对比。

种子代码与参考答案

练习的起点是 --seed-- 中给出的初始代码,此时 h1 是蓝色(.blue-text 声明在后):

<style>
  body {
    background-color: black;
    font-family: monospace;
    color: green;
  }
  .pink-text {
    color: pink;
  }
  .blue-text {
    color: blue;
  }
</style>
<h1 class="pink-text blue-text">Hello World!</h1>

完成练习后的参考答案(--solutions--)如下,可以看到两处改动:<style> 中新增 #orange-text 声明,以及 h1 标签上新增 id="orange-text"

<style>
  body {
    background-color: black;
    font-family: monospace;
    color: green;
  }
  .pink-text {
    color: pink;
  }
  .blue-text {
    color: blue;
  }
  #orange-text {
    color: orange;
  }
</style>
<h1 id="orange-text"  class="pink-text blue-text">Hello World!</h1>

注意两个 class 依然保留在元素上,h1 实际命中的声明有四条(body 继承色、.pink-text.blue-text#orange-text),最终渲染为橙色,正是 id 优先级高于 class 的直观证据。

验收标准:文档内置的自动化断言

该练习文件以 frontmatter + 标记区块(--description----instructions----hints----seed----solutions--)的结构组织,其中 --hints-- 区块内嵌了 7 条 JavaScript 断言,构成了客观的验收标准。逐条拆解如下:

断言 校验内容
classList.contains('pink-text') h1 必须仍带有 pink-text class
classList.contains('blue-text') h1 必须仍带有 blue-text class
getAttribute('id') === 'orange-text' h1 的 id 必须为 orange-text
lengthOf(queryAll('h1'), 1) 页面只能有一个 h1 元素
assert.match(..., /#orange-text\s*{/gi) 源码中必须存在 #orange-text { 声明(先经 removeCssComments 去除注释再匹配)
notMatch(..., /<h1.*style.*>/gi) h1 上不允许出现 style 属性——本篇禁用内联样式这条捷径
getComputedStyle(h1)['color'] === 'rgb(255, 165, 0)' 计算样式必须是橙色 rgb(255, 165, 0),即 orange 的标准 RGB 值

最后一条断言特别值得玩味:它不检查你写的是 orange 还是 rgb(255, 165, 0),而是读取浏览器最终计算出的样式值orange 会被解析为 rgb(255, 165, 0),所以两种写法都能通过;但若 id 声明写错或被 class 覆盖导致颜色不是橙色,断言立刻失败。配合第二条"禁用 style 属性"的断言,这套检查保证了练习真正在验证"用 id 声明覆盖 class 声明"这一知识点,而非其他取巧手段。

优先级阶梯小结

结合 basic-css 区块中这几道连续练习的实验结果,从源码结构看,课程的结论可以整理为如下优先级阶梯(从高到低),且高优先级与声明位置无关:

内联 style 属性        (下一篇验证,见 Override Class Declarations with Inline Styles)
!important 声明        (Override All Other Styles by using Important)
id 选择器(#orange-text)    ← 本篇验证:无条件压过所有 class 声明
后声明的 class(.blue-text)  (Override Styles in Subsequent CSS:同级 class 按声明顺序)
先声明的 class(.pink-text)
元素选择器(body 继承的 color: green)

本篇练习的价值在于用一次最小改动(加一个 id、三条 CSS)实证了阶梯中"id 高于 class"这一层,并与前后练习形成可对照的实验序列:同一元素、同一组冲突声明,仅改变覆盖手段,观察 getComputedStyle 读到的 color 值从 rgb(0, 0, 255)(蓝)变为 rgb(255, 165, 0)(橙),再在后续练习中变为 rgb(255, 255, 255)(白,内联样式)。

需要说明的是,freeCodeCamp 课程文档对"id 永远优先于 class"的表述是针对"单一 id 对多个 class"这一常见场景的教学简化;完整的 CSS 规范优先级(specificity)计算还涉及属性选择器、伪类、多层选择器的叠加比较等,可推断在后续更高级的课程模块中会进一步展开。就本篇练习而言,掌握"id 声明不受书写位置影响地覆盖 class 声明"这一结论,已足以应对绝大多数日常开发中的样式覆盖需求。

延伸阅读路径

登录后查看全文
热门项目推荐
相关项目推荐