CSS 基于具有特定子项的邻居选择元素



这是一个简化的网页结构。

<div>
<div>div 1</div>
<div>div 2<a href="/foo">foo</a></div>
<p>select me</p>
<p>keep me alone</p>
</div>

我想根据里面有a的邻居div来选择所有p。这是我最好的尝试:

document.querySelectorAll('(div > a[href="/foo"]) ~ p')

但显然这不是一个有效的CSS选择器。

如果它有一个邻居div里面有a,是否可以选择p

如果它有一个带有内部的邻居div,是否可以选择 p?

您需要使用:has()选择器,但是完整的解决方案取决于您是要在"实时配置文件"还是"快照配置文件"中使用它:

实时配置文件适用于任何上下文,包括浏览器 CSS 选择器匹配,这是实时的。它包括本文档中定义的每个选择器,但:has()除外:

快照配置文件适用于对性能不是非常敏感的上下文;特别是,它适用于根据静态文档树评估选择器的上下文。例如,DOM 中定义的querySelector()方法应使用快照配置文件。

具体谈论:has()时:

  • .css/<style>样式表规则选择器(这是一个实时上下文(中:
  • .css/<style>样式表规则选择器中,带有客户端脚本以允许使用:has()(这意味着它实际上用作快照上下文(:的,
    • 这里有一个库可以执行此操作: https://www.npmjs.com/package/css-has-pseudo
  • querySelectorquerySelectorAllmatches和其他 DOM 函数(这是一个快照上下文(:的,
    • 但截至 2020 年 5 月,没有浏览器原生支持在这些函数中使用:has()
    • 经过一些粗略的谷歌搜索,我找不到填充物或补丁来添加对querySelector:has()的支持,嘘!

但是假设您可以使用:has()(例如,因为您在 2030 年阅读这篇文章(,那么这个查询就是您所需要的:

div:has(> a[href="/foo"]) ~ p

为什么:has()不在实时配置文件中?

CSS 不支持根据其子元素选择元素的原因有很多(尽管有有限数量的例外,例如:empty:focus-within(,但主要原因是:

  • 这将使CSS选择器的计算成本更高。
  • CSS 旨在处理部分加载的文档,因此在加载文档时,它不会大幅改变外观。

作为一个思想实验:假装浏览器确实支持CSS样式规则中的:has(),请考虑如下所示的HTML文档:

<html>
<head>
<style>
p { background-color: red; }
p:has(div) { background-color: blue; }
</style>
</head>
<body>
<p>foo <div></div></p>
<p>bar</p>
<p>baz <div></div></p>
</body>
</html>
">

foo"和"baz"元素为蓝色,"bar"元素为红色。

现在,如果浏览器将此文档处于部分加载状态,因此到目前为止(在用户的Wi-Fi连接死亡之前(或在下一个TCP数据包到达之前,它只加载了此文档:

<html>
<head>
<style>
p { background-color: red; }
p:has(div) { background-color: blue; }
</style>
</head>
<body>
<p>foo

浏览器需要通过为截断的元素插入自己的结束标记来干净地终止部分加载的文档,如下所示:

<html>
<head>
<style>
p { background-color: red; }
p:has(div) { background-color: blue; }
</style>
</head>
<body>
<p>foo</p>
</body>
</html>

因此,当文档处于此状态时,第一个p将是红色,而不是蓝色 - 然后在用户的 Wi-Fi 连接重新连接(或下一个 TCP 数据包到达(并且页面完成下载后,<p>foo</p>获得<div>,因此现在:has(div)规则适用,<p>foo</p>将突然从红色变为蓝色- 这不好。

现在,在这个人为的例子中,像背景颜色变化这样的微不足道的差异并不重要 - 但如果:has()选择器用于控制页面布局中的一些主要差异(例如body:has(footer) > main { display: grid;(,那么这确实会在页面布局仍在加载时弄乱页面布局 - 这就是为什么基于后代内容的选择器目前不支持当前形式的原因。

(但考虑到父代选择器的绝对实用性和实用性,我想它们将来会重新引入,以某种方式限制规则,仅在DOMContentLoaded触发后使用,或者在选择器不确定时需要默认值或回退。

我可能没有正确理解您的问题,但是如果您只想选择<p>select me</p>,为什么不能将其分配给类?

例如

.HTML:

<div>
<div>div 1</div>
<div>div 2<a href="/foo">foo</a></div>
<p class="selected">select me</p>
<p>keep me alone</p>
</div>

.CSS:

.selected {
color: green;
}

截至目前(据我所知(,您无法从 CSS 中的子项中选择父项,更不用说相邻的"父项"了。 不过,我对你最好的答案是这个,希望它有所帮助。

div + p {
background-color: yellow;
}
<div>
<div>div 1</div>
<div>div 2<a href="/foo">foo</a></div>
<p>select me</p>
<p>keep me alone</p>
</div>

最新更新