前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 :has() relational pseudo-class
CSS层叠与选择器

has() 为什么被叫做"父选择器"?

因为 :has() 可以根据元素包含什么来选中它自己。比如 div:has(> img) 选的是「里面有直接子元素 <img> 的 <div>」。以前 CSS 只能从父选到子,:has() 让你反过来根据子元素的情况给父元素加样式。

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

向上选择的三种用法

  1. 选父元素form:has(:invalid) 选中包含无效输入的表单
  2. 选前面的兄弟h2:has(+ p) 选中后面紧跟 <p> 的 <h2>
  3. 条件判断body:has(.modal) 在弹窗存在时给整个页面加样式

:has() 是实时匹配的,DOM 变化后浏览器会重新计算。大量元素上使用复杂的 :has() 可能影响性能。

核心回答

先记住这个答案

:has() 被叫做「父选择器」是因为它能根据子元素的存在来选中父元素。比如 div:has(> img) 的意思是:如果这个 <div> 里面有直接子元素 <img>,就选中这个 <div>。以前 CSS 只能从上往下选,.parent .child 选的是 .child。:has() 第一次让你根据里面有什么来给外面加样式。

  • :has() 根据后代或兄弟来选中元素本身
  • div:has(> img) 选含直接子图片的容器
  • 优先级和 :is() 一样取参数最高值
  • 不能嵌套使用,不能放在伪元素里

最常见的用法:根据内容给容器加样式

比如一个卡片组件,有图片的卡片和纯文字的卡片排版不同。以前只能在 HTML 上手动加类名区分,现在用 :has() 就能让 CSS 自己判断。

有图片的卡片换布局CSS
/* 普通卡片:纵向排列 */
.card {
  display: flex;
  flex-direction: column;
}

/* 有图片的卡片:横向排列 */
.card:has(> img) {
  flex-direction: row;
}

/* 弹窗打开时禁止页面滚动 */
body:has(.modal-open) {
  overflow: hidden;
}

body:has(.modal-open) 是一个很实用的写法。以前打开弹窗时想给 <body> 加 overflow: hidden,只能用 JavaScript 操作类名。现在只要弹窗元素存在,:has() 就能自动生效。

不只是父选择器:还能选前面的兄弟

:has() 的参数可以用任意组合子。用 +(相邻兄弟)或 ~(通用兄弟)组合子时,它就变成了「前面的兄弟选择器」。

根据下一个兄弟决定样式CSS
/* 后面紧跟段落的标题,加大底部间距 */
h2:has(+ p) {
  margin-bottom: 24px;
}

/* 后面紧跟另一个标题的标题,缩小间距 */
h2:has(+ h2) {
  margin-bottom: 8px;
}

h2:has(+ p) 的意思是:这个 <h2> 后面紧跟着一个 <p> 时,选中这个 <h2>。以前 CSS 的 + 只能选后面的兄弟,现在配合 :has() 就能反过来选前面的。

优先级和限制

:has() 的优先级计算方式和 :is() 一样,取参数中优先级最高的那个选择器。:has(.a) 的优先级是一个类,:has(#b) 的优先级是一个 ID。

:has() 有两个硬限制。第一,不能嵌套::has(:has(.x)) 是不合法的。第二,不能放在伪元素里:::before:has(.x) 也不行。这些限制是为了避免循环依赖和性能问题。

另外要注意性能。:has() 是实时计算的,DOM 每次变化都会重新评估。在大列表上写 li:has(.active) 问题不大,但如果嵌套很深、选择器很复杂,浏览器需要做大量遍历。一般的场景不用担心,除非你在渲染数千个节点的列表。

回答前,多想一步

容易答错的地方

以为 has() 只能选父元素
:has() 的参数可以用 >(子)、+(相邻兄弟)、~(通用兄弟)和空格(后代)。它不只是父选择器,还可以做前向兄弟选择器。
以为 has() 能嵌套使用
:has(:has(.x)) 是不合法的,浏览器不会匹配。规范明确禁止在 :has() 的参数里再放 :has()。
试着用自己的话回答

面试官还会怎么问?

怎么用 has() 做表单验证样式?

form:has(:invalid) 可以在表单中有任何一个字段校验失败时给整个表单加样式,比如显示红色边框或禁用提交按钮的视觉效果。不需要 JavaScript 监听每个字段的变化。

has() 的浏览器兼容性怎么样?

从 2023 年底开始,Chrome、Safari、Firefox 都已支持 :has()。但如果要兼容更早的浏览器版本,需要用 @supports selector(:has(.x)) 做特性检测,不支持的走降级样式。

has() 和 JavaScript 的 querySelector 里用法一样吗?

一样。document.querySelector('div:has(> img)') 在 JavaScript 里也能用,选中第一个包含直接子元素 <img> 的 <div>。:has() 是 CSS Selectors Level 4 的规范,CSS 和 JavaScript 的选择器 API 共享同一套语法。

从一道题,走向一组知识

把知识连起来

层叠与选择器

什么场景下需要手动写 inherit 让子元素继承父属性?

:has() 根据子元素状态影响父元素样式,继承则是父元素的属性值自动传给子元素,方向正好相反。

层叠与选择器

子元素自己写了样式,父元素的继承值还会生效吗?

:has() 可以用来有条件地覆盖继承属性,比如容器内有图片时换一种文字颜色。

参考资料

  • CSS:层叠与选择器参考资料

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

本题目录
  1. 先记住这个答案
  2. 最常见的用法:根据内容给容器加样式
  3. 不只是父选择器:还能选前面的兄弟
  4. 优先级和限制
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

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

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