前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库CSS specificity 优先级计算 示例
CSS层叠与选择器

选择器 ul#nav li.active a:hover 的优先级是多少?

把选择器拆成三列来数:#nav 是 ID 选择器,第一列得 1;.active 和 :hover 是类和伪类,第二列得 2;元素选择器 ul 和 li 以及 a 让第三列得 3。最终优先级是 (1, 2, 3)。

前端进阶之旅 · 一题精讲更新于 2026.09.29
CSS#层叠与选择器
先看核心答案读代码示例
理解线索

优先级三列计数法

  1. ID 列只有 #name 形式才计入,[id=name] 是属性选择器,归第二列
  2. 类/伪类列.active 和 [type=text] 以及 :hover 都在这一列
  3. 元素/伪元素列div 和 a 以及 ::before 在这一列,* 不计入任何列

三列之间不会进位。一个 ID 选择器的 (1, 0, 0) 就赢过 20 个类的 (0, 20, 0)。

核心回答

先记住这个答案

CSS 优先级用三列数值来比较选择器的权重。拿到一个选择器后,把里面的每个部分归入对应的列:ID 选择器归第一列,类选择器、属性选择器和伪类归第二列,元素选择器和伪元素归第三列。对 ul#nav li.active a:hover 来说,#nav 在第一列计 1,.active 和 :hover 在第二列各计 1,ul 和 li 以及 a 在第三列各计 1,最终优先级就是 (1, 2, 3)。

  • ID 列只数 #id,不数 [id=x]
  • 类、属性选择器、伪类都算第二列
  • 元素选择器和伪元素算第三列
  • 通配符 * 和组合符不计入优先级

逐个拆解每一部分

这个选择器看着长,拆开后每个部分都是最基本的选择器类型。

把选择器归位到三列CSS
/*
 * 选择器: ul#nav li.active a:hover
 *
 * ID 列 (A):  #nav           → 1
 * 类列 (B):   .active :hover → 2
 * 元素列 (C): ul li a        → 3
 *
 * 最终优先级: (1, 2, 3)
 */

/* 优先级 (1, 2, 3) */
ul#nav li.active a:hover {
  color: red;
}

/* 优先级 (0, 1, 0),输给上面的 */
.active {
  color: blue;
}

ul 是元素选择器,#nav 是 ID 选择器,li 是元素选择器,.active 是类选择器,a 是元素选择器,:hover 是伪类。每个部分往自己那一列加 1,拼在一起就得到 (1, 2, 3)。 组合顺序不影响结果。把选择器改写成 #nav ul li a.active:hover,优先级仍然是 (1, 2, 3),因为 ID、类、元素的数量没变。组合符 > 和 + 以及 ~ 和空格只描述元素之间的关系,本身不贡献优先级。

三列怎么比大小

比较两个选择器的优先级时从左往右看:先比 ID 列,数字大的直接赢,后面的列不用看。ID 列相等才比第二列,第二列也相等才比第三列。

这个规则意味着列和列之间不存在进位。哪怕你堆了 20 个类选择器,优先级是 (0, 20, 0),遇到一个 #id 的 (1, 0, 0) 还是输。面试的时候经常问「能不能用很多个类覆盖一个 ID」,答案就是不能——除非用 !important 把规则提升到另一个层叠层级。

三列全部相等时,CSS 会用来源顺序来决定:写在后面的规则覆盖前面的。如果项目用了 @layer,层的声明顺序优先于来源位置。

容易归错列的写法

面试常考几种看着像一类、其实归在另一列的选择器。

对比 #nav 和 [id=nav]CSS
/* #nav 是 ID 选择器,优先级 (1, 0, 0) */
#nav { color: red; }

/* [id=nav] 是属性选择器,优先级 (0, 1, 0) */
[id=nav] { color: blue; }

/* :not(.disabled) 本身不计优先级,
 * 括号里的 .disabled 按类选择器计入
 * 下面这条优先级是 (0, 1, 1) */
a:not(.disabled) { color: green; }

[id=nav] 和 #nav 匹配的元素完全一样,但优先级差了一个量级。[id=nav] 是属性选择器,归第二列;#nav 是 ID 选择器,归第一列。面试时把这个区别说清楚,能拿到加分。 :not() 和 :is() 以及 :has() 这三个函数伪类本身不贡献优先级,优先级取决于括号里参数中最高权重的那个选择器。:where() 是特例,不管里面写什么,整体优先级都是零。 伪元素 ::before 和 ::after 以及 ::placeholder 归第三列(元素列),容易和伪类 :hover 或 :focus 搞混。区分方法很简单:两个冒号开头的是伪元素,一个冒号的是伪类。

回答前,多想一步

容易答错的地方

以为数量多就能跨列取胜
三列之间没有进位关系。11 个类选择器的 (0, 11, 0) 仍然输给一个 #id 的 (1, 0, 0)。面试的时候要明确说「不能用数量弥补列级差距」。
忽略了 * 和组合符
通配符 * 匹配所有元素但不计入任何列。div > p 的优先级是 (0, 0, 2),中间的 > 不算。很多人把组合符也数进去,导致算出来的数字偏大。
试着用自己的话回答

面试官还会怎么问?

!important 和内联样式排在哪一列?

它们不在三列体系里。!important 把声明提升到一个更高的层叠层级,所有带 !important 的规则先在内部按优先级排名,再集体赢过所有普通规则。内联样式写在 style 属性里,不经过选择器,优先级天然高于任何选择器规则,只有 !important 能覆盖它。

:where() 的优先级为什么是零?

:where() 是规范设计来给「想匹配但不想提升权重」的场景用的。Tailwind CSS 的预设样式用 :where() 包裹,这样业务代码随便写一个类就能覆盖,不用加 !important。

两个选择器优先级完全相同时怎么办?

来源顺序打破平局:样式表里后出现的规则覆盖前面的。如果用了 @layer,层的声明顺序先于书写位置生效。

从一道题,走向一组知识

把知识连起来

层叠与选择器

为什么一个 ID 选择器就能赢过好几个类选择器?

理解了三列计数,再看为什么一个 ID 就赢过任意多个类。

层叠与选择器

两个相同优先级的规则发生冲突时,CSS 如何决定最终采用哪一条?

两条规则优先级算出来完全相等时,CSS 靠什么打破平局。

参考资料

  • Specificity

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 逐个拆解每一部分
  3. 三列怎么比大小
  4. 容易归错列的写法
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑