CSS有父级选择器吗?

4116

如何选择作为锚点元素的直接父级的 <li> 元素?

例如,我的 CSS 如下:

li < a.active {
    property: value;
}

很明显可以用JavaScript做到这一点,但我希望存在CSS Level 2本身的解决方法。

我正在尝试样式化的菜单是由CMS生成的,所以我不能将活动元素移动到<li>元素中...(除非我主题化菜单创建模块,但我宁愿不这样做)。


9
今天发布的 Safari Tech Preview 137 首次引入了 :has() 选择器的实现。 - TylerH
希望有一种与JavaScript el.parenteElement.parenteElement... 一致的工作方式,比如 a:active:parent:parent 或者甚至是 a::active::parent::parent,用两个分号。这不仅更符合现有伪类的逻辑,而且更易于使用和链接,以便在需要时向上多级。我真的希望有这种实现,因为我真的很讨厌使用 :has(something):它既没有逻辑性,也没有直观性和人体工程学可用性。JavaScript 的方式更好,远胜于 :has()。 - willy wonka
截至今天,大多数现代浏览器都支持最新版本,例如:Chrome / Android 浏览器 / Chrome for Android 105+、Edge 105+、Safari / Safari iOS 15.4+ 和 Opera 91+。只有 Firefox 103 至 106 不支持默认功能,您需要启用它。对于移动设备:(Opera mini、Samsung internet 和 Firefox mobile 尚不支持该功能)。 - Abzoozy
1
@Abzoozy 感谢您的更新。为了使您的有用评论更加完善,您能否定义“它”,并说明哪个 Firefox 首选项启用此功能,直到它正式推出? - RockPaperLz- Mask it or Casket
2
现在在Chrome 105中 https://developer.chrome.com/blog/has-m105/ - northamerican
显示剩余6条评论
33个回答

3447
截至2023年10月,目前还没有一种在所有主要浏览器中都能正常工作的方式来选择CSS元素的父级。
Selectors Level 4 Working Draft规定了一个:has()伪类,它提供了这种功能,以及其他功能。
li:has(> a.active) { /* styles to apply to the li tag */ }

根据https://caniuse.com/css-has,大多数主流浏览器在2022年已经添加了对这个伪类的支持;然而,截至2023年10月,Firefox尚未默认启用该功能。
所以,如果你想要一个支持Firefox、次要浏览器和/或旧版本浏览器的解决方案,那么目前你只能借助JavaScript来实现。

3
看起来 :has() 很快也会在 Firefox 中出现,FYI。根据 Emilio 在 一个小的 Bugzilla 评论 中所说,“今年上半年”(2023)。 - Zack
8
很遗憾,根据此评论发布日期,我们已经进入了2023年下半年,但我们仍然没有FF(FireFox)支持... - Alexander Nied
Webkit无处不在,Firefox是唯一的其他浏览器,如果不支持现代CSS,它将失去市场份额,被Chrome、Edge等取而代之。 - Anh Tran
2
在FF中,如果你需要的话,你可以在about:config中手动启用它,将layout.css.has-selector.enabled更改为true - D.Kastier
也适用于 :has(> svg)!谢谢! - Neil Gaetano Lindberg
1
https://caniuse.com/css-has - Kyborek

336

2
正如@Rodolfo Jorge Nemer Nogueira所指出的那样,可以使用sass(scss)并使用“&”符号实现此操作。然后它将编译为期望的css。如果下一个css版本支持&,那就太好了。 - TamusJRoyce
5
实际上,我认为有一种实验性语法(experimental syntax),与Andrew的语句等效:@supports selector(:has(a)) - xdhmoore
12
SASS最终会将编译结果转换成CSS文件,因为在最终展示页面时仍需使用CSS。 - run_the_race
4
截至今日,大多数最新版本的现代浏览器都默认支持它,例如:Chrome/Android浏览器/Chrome for Android 105+,Edge 105+,Safari/Safari iOS 15.4+和Opera 91+。只有Firefox 103到106不默认支持,您需要启用它。对于移动设备来说:(Opera Mini、三星Internet和Firefox Mobile尚未支持)。 - Abzoozy
是的,除了Safari和Firefox,几乎所有浏览器都基于Chromium。 - Yukulélé
我使用@supports not selector(:has(a, b)) { ... }成功地检查了非兼容浏览器,例如撰写时的Firefox。请参阅https://developer.mozilla.org/en-US/docs/Web/CSS/@supports#testing_for_the_support_of_a_selector。 - Ludovic Kuty

183

我认为在CSS中无法仅选择父元素。

但是,由于您似乎已经拥有一个.active类,将该类移动到li(而不是a)将更容易。这样,您可以仅通过CSS访问lia


4
你不能将伪选择器移到列表项上,因为它不是可聚焦元素。他正在使用 :active 选择器,所以当锚点处于活动状态时,他希望列表项受到影响。列表项永远不会处于活动状态。顺便说一句,很遗憾这样的选择器不存在。如果没有它,使纯CSS菜单完全支持键盘访问似乎是不可能的(使用兄弟选择器可以使使用嵌套列表创建的子菜单出现,但一旦列表获得焦点,它就会再次隐藏)。如果有任何纯CSS的解决方案来解决这个问题,请告诉我。 - user914183
18
请看这个问题,原帖使用的是一个类(class),而不是一个伪选择器(pseudo selector)。我的翻译是否符合您的要求? - jeroen
请查看以下参考资料:链接链接 - Faegheh Mohammadian

149

您可以使用此脚本

*! > input[type=text] { background: #000; }

这将选择任何文本输入框的父级元素。但是,请稍等,还有更多的功能。如果需要,你可以选择指定的父级元素:

.input-wrap! > input[type=text] { background: #000; }

或在其处于活动状态时选择它:

.input-wrap! > input[type=text]:focus { background: #000; }

看看这段 HTML 代码:

<div class="input-wrap">
    <input type="text" class="Name"/>
    <span class="help hide">Your name sir</span>
</div>
您可以在 input 处于活动状态时选择那个 span.help 并显示它:
.input-wrap! .help > input[type=text]:focus { display: block; }

还有很多其他功能,请查看插件文档。

顺便说一句,它在Internet Explorer中可以使用。


5
假设使用jQuery的patent()会更快。不过需要进行测试验证。 - Dan
2
@Idered 当你在CSS声明中使用选择器主题但没有子选择器时,它会失败(#a!单独会抛出错误,#a! p有效),因此其他选择器也无法正常工作,因为会出现“Uncaught TypeError: Cannot call method 'split' of undefined”错误。请参见http://jsfiddle.net/HerrSerker/VkVPs/。 - yunzen
5
@HerrSerker,我认为#a!是无效的选择器,它应该选择什么? - Idered
2
@Idered 我不知道。规范没有说它是非法的。#a! 应该选择自己。至少在 JavaScript 中不应该出现错误。 - yunzen
5
根据我在被接受的答案中的评论,似乎即使在不久的将来,polyfill也可能仍然是必需的,因为浏览器可能永远不会在CSS中实现主题指示器。 - BoltClock
显示剩余5条评论

124

正如其他几位提到的,仅使用CSS无法样式化元素的父级元素,但以下内容可使用 jQuery 实现:

$("a.active").parents('li').css("property", "value");

24
"<"选择器不存在(使用jQuery 1.7.1已经验证)。 - Rob W
7
也许那个 < 语法在2009年可行,但我已将其更新(适用于2013年)。 - Alastair
6
更好的方法是使用jQuery内置的:has()选择器: $("li:has(a.active)").css("property", "value");。它与CSS 4提议的!选择器类似。另请参见::parent选择器、.parents()方法、.parent()方法。 - Rory O'Kane
9
与其使用.css("property", "value")来为选定元素设置样式,通常你应该使用.addClass("someClass")并在CSS中定义.someClass { property: value } (来源)。这样,你可以利用完整的CSS功能及任何预处理器来注释样式。 - Rory O'Kane

88

没有父级选择器,就像没有前一个同级选择器一样。不使用这些选择器的一个好原因是因为浏览器必须遍历元素的所有子元素来确定是否应该应用类。例如,如果您编写了以下代码:

body:contains-selector(a.active) { background: red; }

然后浏览器将不得不等待直到它加载和解析了 </body> 之前的所有内容,才能确定页面是否应该是红色的。

为什么我们没有父级选择器这篇文章详细解释了这个问题。


16
实际上,选择器会让一个非常快的浏览器看起来变慢。 - Salman A
10
我相信浏览器开发者会推出一个实现,其速度(至少)与JavaScript版本一样快,而人们最终使用的也是这个版本。 - Marc.2377
2
@Marc.2377 如果你在你的网站上尝试以上JS示例,我将永远不会访问它。另一方面,我认为大多数情况下,你只关心直接子元素,所以如果仅限于直接子元素,它将是一个很好的补充,而且影响不大。 - xryl669

79

伪元素:focus-within允许在后代元素获得焦点时选择其父元素。

如果一个元素有tabindex属性,它就可以被聚焦。

支持 focus-within 的浏览器

Tabindex

示例

.parent:focus-within {
  background: hsl(199deg, 65%, 73%);
}

/* demo styles */
body {
  margin: 0;
}
.parent {
  background: hsl(0, 0%, 80%);
  min-height: 100vh;
  display: grid;
  place-content: center;
}
.child {
  background: hsl(0, 0%, 0%);
  color: white;
  padding: 3rem;
  outline: 0;
  cursor: pointer;
  font: 18px/1.25 sans-serif;
  width: 20ch;
}
<div class="parent">
  <div class="child" tabindex="0">
    Click or Focus on me, my parent will change.
  </div>
</div>


3
在我的情况下这很有效,谢谢!只是一个提示,如果您将颜色更改为父级而不是同级,则示例会更具说明性,这可以通过将.color:focus-within .change替换为.color:focus-within来实现。在我的情况下,我正在使用bootstrap nav-bar,在活动时将类添加到子元素,并且我想要向父级.nav-bar添加类。我认为这是一个相当常见的场景,其中我拥有标记,但组件css+js是bootstrap(或其他),因此我无法更改其行为。尽管如此,我可以添加tabindex并使用此CSS。谢谢! - cancerbero
1
高效回答!我想为我们中的复制粘贴者添加一个警告 - 当为非交互式元素添加焦点时,通常被认为是反模式添加非零 tabindex 。只需使用 0 或它将始终首先定位到该元素,而不考虑文档流。我更新了答案,将它的 tabindex 设置为零。 - Todd

69

在CSS 2中没有办法实现这个。您可以将该类添加到li并引用a

li.active > a {
    property: value;
}

4
通过将a元素设置为display:block,您可以样式化它以适应整个li区域。如果您可以解释您需要的样式,也许我可以帮您提供一个解决方案。 - Josh

40

尝试将a元素的显示方式切换为block,然后使用任何样式。 a元素将填充li元素,并且您可以按照自己的意愿修改其外观。不要忘记将li的内边距设置为0。

li {
  padding: 0;
  overflow: hidden;
}
a {
  display: block;
  width: 100%;
  color: ..., background: ..., border-radius: ..., etc...
}
a.active {
  color: ..., background: ...
}

36

你可能可以使用CSS选择器“普通兄弟组合器”来实现你想要的效果:

E ~ F {
    property: value;
}

这将匹配任何在E元素之前的F元素。


“.component-one:visible ~ body{ background-color: red; }” 不起作用。 - e-info128
1
@F-Natic 我并不惊讶它不能工作。这不是有效的CSS(CSS中没有:visible伪类)。body也是html的直接且唯一后代。 - TylerH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接