CSS :has() 选择器详解:为什么它是“父选择器”?如何实现真正的容器查询?

一、前言

在传统的 CSS 中,我们只能根据元素的自身属性、类名、ID 或其子元素/兄弟元素来设置样式,却无法根据其父元素或后代元素的状态来改变自身样式

直到 :has() 选择器的出现,这一局面被彻底改变。

:has() 被称为 “父选择器”“容器选择器”,是 CSS 选择器的一次革命性升级。它不仅让 CSS 拥有了更强的表达能力,还为 容器查询(Container Queries) 提供了重要支持。

本文将深入解析 :has() 的语法、用法与实战场景,带你掌握这一现代 CSS 强大特性。


二、什么是 :has() 选择器?

:has() 是一个 关系伪类选择器(Relational Pseudo-class),用于匹配包含特定后代元素的父元素

✅ 语法:

parent:has(descendant) {/* 样式规则 */
}

🔍 简单理解:

“选择那些 包含 某个特定后代元素的父元素”。


三、基本语法与示例

1. 基础用法:匹配包含特定子元素的父级

<div class="card"><h3>标题</h3><p>这是一段描述文字。</p>
</div><div class="card"><h3>标题</h3><!-- 没有 p 元素 -->
</div>
/* 只有包含 <p> 的 .card 才有边框阴影 */
.card:has(p) {box-shadow: 0 4px 6px rgba(0,0,0,0.1);border-radius: 8px;
}

2. 支持复杂选择器

/* 包含 .error 类的表单 */
.form:has(.error) {border: 2px solid #e74c3c;
}/* 包含图片的段落,增加行高 */
p:has(img) {line-height: 1.8;
}/* 包含至少两个子项的列表 */
ul:has(li:nth-child(2)) {background: #f8f9fa;
}

四、为什么说 :has() 是“父选择器”?

在 CSS 历史上,一直无法直接选择“父元素”。例如:

“如何选中包含 <input type="text"><label>?”

过去只能通过 JavaScript 或调整 HTML 结构解决。

现在,:has() 让 CSS 原生支持“向上选择”:

<label>用户名:<input type="text" name="username">
</label>
/* 选中包含 text input 的 label */
label:has(input[type="text"]) {font-weight: bold;color: #333;
}

✅ 这就是所谓的“父选择器”能力。


五、实战场景:真正的“容器查询”(Container Queries)

CSS 容器查询(@container)允许组件根据其容器大小而非视口大小来响应。:has() 可与之结合,实现更智能的布局。

示例:卡片根据内容动态调整

<div class="container" style="width: 300px;"><article class="card"><img src="image.jpg" alt="图片"><h3>带图片的卡片</h3><p>这是一段描述。</p></article>
</div><div class="container" style="width: 300px;"><article class="card"><h3>纯文本卡片</h3><p>没有图片。</p></article>
</div>
/* 启用容器查询 */
.container {container-type: inline-size;
}.card {display: grid;gap: 12px;padding: 16px;
}/* 如果卡片包含图片,使用两行布局 */
.card:has(img) {grid-template-rows: auto 1fr;
}/* 容器查询 + :has():小容器中,有图片的卡片改为单列 */
@container (max-width: 320px) {.card:has(img) {grid-template-columns: 1fr;grid-template-rows: auto auto 1fr;}
}

✅ 组件真正实现了“内容感知”与“容器感知”。


六、高级用法与技巧

1. 多条件匹配(与逻辑)

/* 同时包含 h2 和 .btn 的 header */
header:has(h2):has(.btn) {padding: 2rem;background: #e3f2fd;
}

2. 否定匹配(结合 :not())

/* 不包含图片的卡片 */
.card:not(:has(img)) {font-size: 1.1em;
}

3. 表格行高亮(悬停整行)

/* 当 td 被悬停时,高亮其父 tr */
tr:has(td:hover) {background-color: #f5f5f5;
}

七、浏览器兼容性

浏览器支持情况
Chrome105+ ✅
Edge105+ ✅
Safari15.4+ ✅
Firefox121+ ✅
iOS Safari15.4+ ✅

📊 数据来源:Can I use :has()

⚠️ 注意:目前 IE 和旧版浏览器不支持,生产环境建议结合渐进增强策略使用。


八、与 JavaScript 的对比

过去类似功能需 JS 实现:

document.querySelectorAll('.card').forEach(card => {if (card.querySelector('img')) {card.classList.add('has-image');}
});

:has() 的优势:

  • 无需 JS,减少脚本依赖。

  • 性能更高,由浏览器原生优化。

  • 更简洁,样式逻辑集中在 CSS 中。


九、总结

:has() 选择器是 CSS 发展史上的里程碑特性:

  • ✅ 实现了“父选择器”功能,打破 CSS 选择方向限制。

  • ✅ 与容器查询结合,推动组件化、响应式设计进入新阶段。

  • ✅ 减少对 JavaScript 的依赖,提升样式表达能力。

随着浏览器支持度不断提升,:has() 将成为现代前端开发的必备技能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/96682.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/96682.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

李宏毅 Deep Learning

感谢李宏毅老师qwq1. 基础概念1.1 Machine Learning问题引出&#xff1a;预测后面几天的观看人数&#xff1b;初步构建模型&#xff1a;拟合效果不好&#xff0c;就是在原数据上平移了一段距离&#xff1b;此处构建模型的本质&#xff1a;利用特征工程&#xff0c;将“多维特征…

【AI论文】分享即关爱:基于集体强化学习经验共享的高效语言模型(LM)后训练方法

摘要&#xff1a;利用强化学习&#xff08;RL&#xff09;对语言模型&#xff08;LMs&#xff09;进行后训练&#xff0c;无需监督微调即可增强其复杂推理能力&#xff0c;DeepSeek-R1-Zero便证明了这一点。然而&#xff0c;要有效利用强化学习训练语言模型&#xff0c;需要进行…

工业网关在汽车冲压车间的应用:EtherNet/IP转EtherCAT集成实践

在汽车零部件冲压车间中&#xff0c;生产线的高效协同与精准控制是提升整体产能的关键。随着自动化设备的多样化&#xff0c;不同协议的设备之间的通信成为技术难点。例如&#xff0c;罗克韦尔PLC通常采用EtherNet/IP协议&#xff0c;而许多高性能机械臂则依赖EtherCAT协议。如…

【底层机制】【C++】std::move 为什么引入?是什么?怎么实现的?怎么正确用?

C++底层机制推荐阅读 【C++基础知识】深入剖析C和C++在内存分配上的区别 【底层机制】【C++】vector 为什么等到满了才扩容而不是提前扩容? 【底层机制】malloc 在实现时为什么要对大小内存采取不同策略? 【底层机制】剖析 brk 和 sbrk的底层原理 【底层机制】为什么栈的内存…

Redis面试相关

数据过期策略 惰性删除 当用到那个key的时候再检查是否过期&#xff0c;过期则删除&#xff0c;有效则返回key 优点是可以节省检查过期的时间 缺点是会浪费内存 定期删除 每隔一段时间对一些key进行检查并且删除里面的过期key 有两种模式 slow模式是定时任务&#xff0c;频率是…

知识输出零散没有体系怎么办

当面临知识输出零散、不成体系的困境时&#xff0c;其根本原因在于未能建立一个从输入、整合到输出的闭环系统。要解决这一问题&#xff0c;核心在于构建个人知识管理体系、掌握结构化思维与表达能力、运用合适的工具与方法进行固化、持续实践并迭代优化。这意味着&#xff0c;…

【C语言选择排序算法详解】+ 算法性能优化 + 动态演示实现

文章目录一、算法介绍二、算法特点三、代码实现与解析四、代码解析1. 打印数组函数2. 选择排序核心逻辑3. 动态展示实现4. 主函数五、算法优化思路与实现优化1&#xff1a;减少交换次数优化原理&#xff1a;优化2&#xff1a;双向选择排序优化原理&#xff1a;优化3&#xff1a…

栈(Java)

提示&#xff1a;多练才是王道,加油٩(๑❛ᴗ❛๑)۶ 栈Java1. 栈2. Java中栈的其中两种实现方式2.1 Stack类2.1.1 Stack的模拟实现2.2 LinkedList类3. 典型习题讲解3.1 逆波兰表达式求值3.2 匹配括号3.3 合理弹出序列3.4 最小栈1. 栈 栈是一种特殊的线性表,其只允许在固定的一…

LayaAir鼠标(手指)控制相机旋转,限制角度

切换天空盒脚本挂载到相机身上 const { regClass, property } Laya;regClass() export class SmoothCameraController extends Laya.Script {declare owner: Laya.Camera;// 旋转灵敏度property({ type: Number, name: "旋转灵敏度" })public rotationSensitivity:…

【数据结构入门】排序算法(4)归并排序

目录 1.排序的原理 1.1 保证子数组有序 1.2 时间复杂度 2. 递归实现 2.1 思路 2.2 代码 3. 非递归实现 3.1 思路 3.2 代码 4.面试题 4.1 题目 4.2 思路 1.排序的原理 归并排序是外排序&#xff0c;所谓外排序就是说能够对文件中的数据进行排序。 ①首先&#xff…

FLEXSPI_Init 硬件故障问题

使用官方例程发现FLEXSPI_Init会引起硬件故障&#xff0c;查阅相关帖子发现主要有两个可能&#xff1a;1、外部闪存配置差异修改 LUT&#xff08;查找表&#xff09;命令&#xff1a;示例中擦除扇区命令为 0xD7&#xff0c;写状态寄存器命令为 0x01&#xff0c;需分别改为 闪存…

如何用 Rust 重写 SQLite 数据库(一):项目探索

要使用 Rust 重写 SQLite 数据库&#xff0c;我们需要实现一个简化的关系型数据库核心功能&#xff08;如 SQL 解析、存储引擎、事务管理&#xff09;。以下是一个分步实践指南&#xff0c;包含关键代码示例。一、项目规划 我们将实现一个超简化数据库 MiniSQL&#xff0c;支持…

JVM之堆(Heap)

一、堆的核心特性 唯一性与共享性 每个JVM实例仅有一个堆&#xff0c;所有线程共享&#xff0c;但可通过线程私有缓冲区&#xff08;TLAB&#xff09;减少多线程分配冲突。内存结构演变 JDK 7及之前&#xff1a;堆分为新生代&#xff08;Young&#xff09;、老年代&#xff08;…

单片机的RAM与ROM概念

RAM与ROM1、RAM与ROM2、 bss、data、heap、stack、text详细讲解3、详细探讨 TCM、OCRAM 和 HBNRAM 之间的区别及其具体作用。3.1、TCM&#xff08;Tightly Coupled Memory&#xff09;3.2、 OCRAM&#xff08;On Chip RAM&#xff09;3.3、HBNRAM (Hibernate RAM)3.4、总结1、R…

实验3:事件处理(2学时)

实验目的&#xff08;1&#xff09;熟练掌握 v-on 指令的用法&#xff0c;学会使用 v-on 指令监听 DOM 元素的事件&#xff0c;并通过该事件触发调用事件处理程序。&#xff08;2&#xff09;掌握v-on 指令修饰符的基本用法。实验内容实现购物车功能的拓展&#xff08;商品数量…

商品库存扣减方案

文章目录1. Lua脚本 Redis&#xff08;业界首选&#xff0c;综合最优&#xff09;2. Redis原子命令&#xff08;DECRBY 结果校验&#xff09;3. Redis事务&#xff08;MULTI/EXEC&#xff09;4. 分布式锁&#xff08;基于Redis实现&#xff09;5. Redisson客户端封装&#xf…

关于在阿里云DMS误操作后如何恢复数据的记录

前言 昨天因客户员工操作错误&#xff0c;导致快递单号和订单互换。客户员工那边让笔记修改数据。 于是笔者写下如下SQL来操作&#xff0c;导致了灾难性事故。 update t_order_fed_ex_record set tracking_number 884102170661, master_tracking_number 884102170661, push…

【操作系统核心知识梳理】线程(Thread)重点与易错点全面总结

在多任务操作系统中&#xff0c;线程是比进程更轻量的执行单元&#xff0c;理解线程的特性和实现方式是掌握并发编程的基础。本文系统梳理了线程相关的核心知识点和常见误区&#xff0c;助你夯实操作系统基础。一、线程的基本概念与引入目的 1.1 什么是线程&#xff1f; 线程是…

深入理解 Python 中的 `__call__` 方法

化身为可调用的对象&#xff1a;深入理解 Python 中的 __call__ 方法 引言&#xff1a;函数与对象的边界模糊化 在 Python 中&#xff0c;我们最熟悉的概念莫过于函数&#xff08;Function&#xff09; 和对象&#xff08;Object&#xff09;。函数是可调用的&#xff08;calla…

云服务器使用代理稳定与github通信方法

使用SSH反向隧道 (SSH Reverse Tunneling) 利用SSH连接在您的本地电脑和云服务器之间建立一个反向的加密通道。 原理&#xff1a; 从本地电脑发起一个SSH命令到您的云服务器&#xff0c;这个命令会告诉云服务器&#xff1a;“请监听您自己的某个端口&#xff08;例如&#xff1…