CSS 的 :has
选择器可帮助您选择包含与您传递给 :has()
函数的选择器匹配的元素的元素。它本质上是一个“父级”选择器,尽管它远比这更有用。例如,假设您想选择所有 <div>
,但仅在它们包含 <p>
时。这就是我们能做到的
div:has(p) {
background: red;
}
/*
<div> <!-- selected! -->
<p></p>
<div>
<div></div> <!-- not selected -->
<div> <!-- not selected -->
<section></section>
</div>
*/
尽管在我写这篇文章的时候它在任何浏览器中都不受支持,但它现在已在 Safari 技术预览版 137 中推出,因此它正在开始发生!
非常方便,对吧!以下是一个示例。假设您希望在标题后添加空格。当然!在您的 h2
上添加一些 margin-block-end
应该就可以了。但是……如果有一个副标题呢?现在我们可以根据副标题是否存在来选择父级并调整间距。
h2,
.subtitle {
margin: 0 0 1.5rem 0;
}
.header-group:has(h2):has(.subtitle) h2 {
margin: 0 0 0.2rem 0; /* reduce spacing on header, because subtitle will handle it */
}
/*
<div class="header-group">
<h2>Blog Post Title</h2> <!-- main spacing applied here -->
</div>
<div class="header-group">
<h2>Blog Post Title</h2>
<div class="subtitle"> <!-- main spacing applied here -->
This is a subtitle
</div>
</div>
*/

我对 :has
的看法是:它是一个父级选择器伪类。这就是 CSS 术语中的“它允许您更改父级元素,前提是它有一个子级或另一个跟随它的元素”。这可能感觉很奇怪!它可能会破坏您对 CSS 工作原理的思维模型。这就是我习惯思考 CSS 的方式
.parent .child {
color: red;
}
您只能从上到下进行样式设置,从父级到子级,但永远不能向上回到树的顶部。:has
完全改变了这一点,因为到目前为止,CSS 中还没有父级选择器,而且有一些很好的理由。由于浏览器解析 HTML 和 CSS 的方式,如果满足某些条件,选择父级可能会导致各种性能问题。
如果我坐下来仔细考虑今天可能使用 :has
的所有方法,我会有点头疼。它将打开一个以前不可能仅仅用 CSS 实现的潘多拉魔盒。
另一个示例:假设我们只希望将样式应用于包含图像的链接
a:has(> img) {
border: 20px solid white;
}
这偶尔会很有用。我还可以看到 :has
用于根据元素的内容有条件地向元素添加边距和填充。那将会很酷。
:has
选择器是CSS 选择器级别 4 规范的一部分,与包含极其有用的 :not
伪类的规范相同。
您可以争辩说,CSS :has
选择器比仅仅是“父级”选择器更强大,这正是 Bramus 所做的事情!就像上面的副标题示例一样,您并不一定最终选择父级,您可能会在 has 条件中选择父级,但最终会从中选择子级元素。
/* Matches <figure> elements that have a <figcaption> as a child element */
figure:has(figcaption) { … }
/* Matches <img> elements that is a child of a <figure> that contains a <figcaption> child element */
figure:has(figcaption) img { … }
在那里,您可以快速看到第二个选择器正在选择一个子级 <img>
,而不仅仅是 <figcaption>
的父级。
选择器列表
您可以将其链接
article:has(h2):has(ul) {
}
或为其提供一个选择器列表
article:has(h2, ul) {
}
并且该列表很宽容:在 W3C 于 2020 年 12 月通过一项决议以响应报告的问题 后,该列表不再“宽容”。因此,如果选择器列表包含一个无效参数,则整个列表将被忽略
/* 👎 */
article:has(h2, ul, ::-blahdeath) {
/* ::blahdeath is invalid, making the entire selector invalid. */
}
一种解决方法是在其中嵌套一个更宽容的选择器,例如 :is()
或 :where()
/* 👍 */
article:has(:where(h2, ul, ::-blahdeath)) {
/* :where is a forgiving selector, making this valid. */
}
测试支持
@supports(selector(:has(p))) {
/* Supported! */
}
:not()
选择器是同一规范的一部分……
与 :has
不同,:not
确实 具有相当不错的浏览器支持,我前几天第一次使用它
ul li:not(:first-of-type) {
color: red;
}
太棒了,我还喜欢它多么易读;您不必见过这行代码就能理解它在做什么。
您可以使用 :not
的另一种方法是用于边距
ul li:not(:last-of-type) {
margin-bottom: 20px;
}
因此,不是最后一个项目的每个元素都获得边距。如果您在卡片中有一堆元素,这将很有用,比如这样
:is()
和 :where()
……以及 CSS 选择器级别 4 也是包含 :is
选择器的规范,该选择器今天可以在许多浏览器中使用,如下所示
:is(section, article, aside, nav) :is(h1, h2, h3, h4, h5, h6) {
color: #BADA55;
}
/* ... which would be the equivalent of: */
section h1, section h2, section h3, section h4, section h5, section h6,
article h1, article h2, article h3, article h4, article h5, article h6,
aside h1, aside h2, aside h3, aside h4, aside h5, aside h6,
nav h1, nav h2, nav h3, nav h4, nav h5, nav h6 {
color: #BADA55;
}
更多信息
就是这样!:has
应该很快就能派上用场,它的兄弟 :is
和 :not
已经非常有用,而这仅仅是这个新规范中可用内容的一小部分——仅三个 CSS 伪类。
- Adrian Bece — 遇见
:has
,一个原生 CSS 父级选择器(以及更多) - Bramus Van Damme — CSS 的
:has()
选择器远不止是一个“父级选择器” - Michelle Barker — :has() 已在 Safari 中推出
使用
:has()
阅读 CSS 选择器确实需要一段时间才能适应。不过,我真的很期待
:where()
!:how()
那会怎么运作呢?老实说,能够为包含图像的链接设置样式将是一件好事;我构建的许多网站都有这些过于花哨的链接样式,当内容是内联图像时,这些样式就会崩溃。我不得不编写各种修复程序来修补标记或需要一些包装类来让我定位那些旨在不加修饰的可点击图像的链接。
是的,这是
has
的常见用法,但说实话,浏览器可能需要几年时间才能支持它,而且这还取决于它是否最终能够通过。不过,该语法似乎非常不一致。我可以理解
:has(p)
包含<p>
元素。但是:has(+ div)
作为后面跟着一个<div>
元素似乎并不一致。我希望它包含一个由任何其他元素前置的<div>
元素。那将如何表达呢?通过:has(* + div)
吗?我这里也是,一开始我以为 has 是一个层次结构选择器,用于主元素内部的任何内容,但它更像是对主元素为真的一些东西。
例如
div has:(p) = div p
规则应用于左侧元素“div”,而不是右侧元素“p”
h1 has:(+ div) = h1 + div
规则应用于 h1 而不是 div,就像平常一样
您前几天第一次使用
:not
吗?太棒了!我最近听了一场演讲,CSS 工作组的一位成员说,他们在一系列技术会议中确定,在找到解决添加它所产生的循环引用问题的变通方法之前,
:has()
无法实现。这就是这个如此有用的想法目前没有浏览器支持的原因。我从未完全理解这一点——我们不能让开发人员负责解决这些问题吗?毕竟,它适用于我们可能会自食其果的其他愚蠢错误,例如
p:hover {transform: scale(0.9)}
可能会导致边缘出现一些抖动,但那是我们开发人员需要处理的事情。Adblock Plus 过滤器支持一个名为 "has" 的伪选择器。他们的选择器是
-abp-has
。我发现它在选择具有生成 ID 和类的 div 时非常有用,但它具有唯一的子 DOM 结构。 https://adblockplus.org/filter-cheatsheet#elementhideemulation对于包含复选框的标签来说,这将是一件好事。:has(:checked)。或者 div.form-control:has(input:invalid)
我相信还有很多其他的用例。
:has() 需要应用于直接子元素,还是可以更像一个包含关系?
例如:body:has(.printArea) {
// 隐藏所有内容,除了 printArea
}
这样,如果内容创建者定义了一个 printArea 类,它就会被使用,但如果没有,则会使用网站默认的 @media print 偏好设置。
嗯,:not() 真的很老了。它从 2006 年开始在 Firefox 中可用,从 2008 年开始在 Safari 中可用。
这个选择器太有用了,我期待它的实现很久了。
嗨,这是一篇不错的文章,但我没有理解您使用的特殊操作符,例如 +、 - 和 > 的含义。这些操作符的含义是什么?还有哪些其他的操作符可用?
这些是普通的 CSS 选择器组合符。您可以找到它们 在 MDN 上,并阅读更多关于它们的信息 在 CSS 技巧上 :-)
has()
、not()
、is
。我认为
has()
应该像这样使用div has(.show){ display: block }
我期待
where()
、if()
、with()
支持它作为 CSS 选择器将是极好的。我发现它在我过去经常使用 jQuery 的时候非常有用(参见 https://api.jqueryjs.cn/has-selector/)。
:has 伪选择器已经存在于愿望清单中多年,甚至可能超过十年...但浏览器供应商反复重申,它无法实现。在我们听到相反的消息之前,我不会浪费时间去研究它。
Selector :not() 在 CSS3 中定义,但它只能包含一个选择器。如果你知道自己在做什么,它仍然非常有用(例如 div:not(.hidden) { display: block })或需要缩短一些更高级的选择器(例如 li:not(:first-of-type):not(:last-of-type) { … })。
我热切地期待 :has() 的采用。想象一下
目前,检查这一点的唯一方法是使用 JS。在 CSS 中以干净的方式执行它将是一件美事!
还有很多其他的可能性!
我们知道它是否可以嵌套吗?
div:has(a:has(img))
???呸,这对于可读性来说不太好。
是的,伙计。
嗨,我有一个问题。
我们有父元素 A
以及它里面的子元素 B
<A>
<B></B>
</A>
<A>
<B></B>
</A>
<A>
<B></B>
</A>
每个元素 B 都获得一个类,其中它的背景颜色是例如,所以代码如下所示
<A>
<B class="red"></B>
</A>
<A>
<B class="green"></B>
</A>
<A>
<B class="blue"></B>
</A>
我的问题是,是否可以根据其子元素 B 的背景颜色来设置父元素 A 的背景颜色?
谢谢 :)
当
:has()
被支持时,这是可能的,是的。这可以用作
:*-within
伪类的替代方案。不是吗?
一切正常,但石头没有正确地安装!:)
这两件事有什么区别?
div:has(p) {color: #000}
div p {color: #000}
为什么我应该使用 :has() 选择器?
div:has(p) - "color" 用于此 "div" 的所有内容,但前提是此 "div" 包含 "p" 标签。
div p - "color" 仅用于 "div" 中的 "p" 标签。
是否也可以将 CSS 选择器与 CSS 操作符组合使用?
我正在尝试突出显示其中一个单元格包含
所以我
tbody.plugins tr td.plugin-title p img[src*=”pluginname”] { background-color: var(–postpone-update-alert) !important; }
需要变成类似
tbody.plugins tr:has(td.plugin-title p img[src*=”pluginname”]) { background-color: var(–postpone-update-alert) !important; }
因为我想将突出显示应用于整行,但它不起作用...
这可能吗?还是我只是忽略了什么?
article:has(h2, ul)
的含义是什么?