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个回答

31

2023年更新的CSS选择器4

在CSS选择器4规范中,CSS引入了一个新的选择器叫做:has(),它终于让我们能够选择父元素了。这意味着我们将能够选择具有特定子元素的CSS元素。这已经在Safari中得到支持,并且也在Chrome 105中得到支持。完整的支持表在这里显示。

父选择器的工作原理

在CSS中,如果我们想选择某个元素,我们使用沿DOM下降的选择器。

例如,选择一个div标签内的p标签看起来像这样:

 div p {
   color: red;
}

直到现在,我们无法真正选择那些包含

标签的

标签,这意味着我们不得不借助JavaScript来实现。之所以没有在CSS中实现这个功能,主要是因为这是一个相当昂贵的操作。CSS的解析速度相对较快,但选择父标签需要相对较大的处理量。
使用:has选择器,我们现在可以选择具有

子元素的

元素,或者任何其他常规选择器的组合。
例如,选择具有子元素

现在看起来像这样:
div:has(p) {
  color: red;
}

这将使任何具有子元素

变为红色。

将父选择器与其他选择器结合使用

就像任何其他CSS选择器一样,我们可以将其与特定情况相结合使用。 例如,如果您只想选择具有直接子元素的

标签:

div:has(> span) {
  color: red;
}

根据:has的词汇表达,它不仅仅局限于父级选择。
例如,下面我们可以选择一个具有兄弟节点divspan
span:has(+ div) {
color: red;
}

甚至可以通过使用:not()选择器选择没有子元素的元素。
例如,以下代码将选择没有p子元素的任何div:
div:not(:has(p)) {
 color: red;
}

在CSS中选择只包含文本的元素

CSS中一个非常常见的问题是:empty标签不能选择包含任何文本的元素 - 所以有时候一个元素可能只包含一个空格,而:empty不会生效。而:has选择器给了我们选择只包含文本节点而没有其他子元素的元素的能力。

虽然这不是一个完美的解决方案来简单地选择只包含空格的:empty元素(因为这将选择任何只有文本而没有其他HTML DOM元素的元素) - 但它确实给了我们选择只包含文本节点的DOM元素的能力,这是以前不可能的。我们可以通过以下代码实现:

div:not(:has(*)) {
  background: green;
}

1
这应该是截至2023年的新接受答案。 - undefined

28

据我所知,在 CSS 2 中没有这个功能。虽然 CSS 3 拥有更强大的选择器,但并不是所有浏览器都能一致实现。即使使用了改进后的选择器,我也认为它不能完全满足您在示例中描述的要求。


26
这是与“选择器Level 4”规范相关的最受讨论的方面。
通过在给定选择器后面添加感叹号(!),选择器将能够根据其子元素样式化一个元素。
例如:
body! a:hover{
   background: red;
}

如果用户悬停在任何锚点上,将设置红色背景颜色。

但是我们必须等待浏览器的实现 :(


1
"!" 特性已被替换为 ':has()' https://drafts.csswg.org/selectors/#changes-2013 - ScarpMetal

26
你可以尝试使用超链接作为父元素,然后在鼠标悬停时更改内部元素。像这样:

a.active h1 {color:red;}

a.active:hover h1 {color:green;}

a.active h2 {color:blue;}

a.active:hover h1 {color:yellow;}

通过这种方式,您可以根据父元素的鼠标悬停来更改多个内部标签的样式。


1
这是正确的,但是限制了a标签内的标记代码仅适用于某些元素,如果您想符合XHTML标准。例如,您不能在a中使用div,否则会收到违反模式的警告。 - Ivaylo Slavov
2
完全正确,Ivaylo!“a”是非块元素,因此不能在其中使用块元素。 - riverstorm
2
在HTML5中,将块元素放置在链接内是完全可以的。 - Matthew James Taylor
2
如果语义上有问题,HTML5 就不会允许它存在,而之前也不存在。 - BoltClock
@BoltClock 在遥远的未来回复,不过我怀疑 Matthew 对 HTML5 的评论更多是为了将“HTML”与“XHTML”进行对比(根据 Ivaylo/riverstorm 的说法,这在 XHTML 中是不允许的),而不是将 HTML 5 与之前的 HTML 版本进行对比。 - TylerH

25
我知道楼主正在寻找一个 CSS 解决方案,但是使用 jQuery 很容易实现。在我的情况下,我需要找到包含在子 <li> 中的 <span> 标签的 <ul> 父标签。jQuery 有 :has 选择器,因此可以通过其包含的子元素来识别父元素:
$("ul:has(#someId)")

将选择具有带id为someId的子元素的ul元素。或者回答最初的问题,类似以下内容的代码应该可以解决问题(未经测试):

$("li:has(.active)")

4
жӮЁеҸҜд»ҘдҪҝз”Ё $yourSpan.closest("ul") жқҘиҺ·еҸ–жӮЁзҡ„ span е…ғзҙ зҡ„зҲ¶зә§ ulгҖӮе°Ҫз®ЎеҰӮжӯӨпјҢжҲ‘и®ӨдёәжӮЁзҡ„еӣһзӯ”е®Ңе…ЁдёҺдё»йўҳж— е…ігҖӮжҲ‘们еҸҜд»ҘдҪҝз”Ё jQuery жқҘеӣһзӯ”жүҖжңүдёҺ CSS зӣёе…ізҡ„й—®йўҳгҖӮ - Robin van Baalen

22

这是一个使用pointer-eventshover的小技巧:

<!doctype html>
<html>
    <head>
        <title></title>
        <style>
/* accessory */
.parent {
    width: 200px;
    height: 200px;
    background: gray;
}
.parent, 
.selector {
    display: flex;
    justify-content: center;
    align-items: center;
}
.selector {
    cursor: pointer;
    background: silver;
    width: 50%;
    height: 50%;
}
        </style>
        <style>
/* pertinent */
.parent {
    background: gray;
    pointer-events: none;
}
.parent:hover {
    background: fuchsia;
}
.parent 
.selector {
    pointer-events: auto;
}
        </style>
    </head>
    <body>
        <div class="parent">
            <div class="selector"></div>
        </div>
    </body>
</html>


14

有一个插件扩展了CSS,包括一些非标准特性,可以在设计网站时帮助解决一些问题。这个插件叫做EQCSS

EQCSS添加的其中一个功能是父选择器。它适用于所有浏览器,包括Internet Explorer 8及以上版本。下面是其格式:

@element 'a.active' {
  $parent {
    background: red;
  }
}
所以在这里,我们对每个元素 a.active 开启了一个元素查询,在该查询中的样式中,例如 $parent 是有意义的,因为有一个参考点。浏览器可以找到父级,因为它与 JavaScript 中的 parentNode 非常相似。 这是一个演示 $parent另一个在 Internet Explorer 8 中可用的 $parent 演示,以及一张截图,以防您没有 Internet Explorer 8 用于测试
EQCSS 还包括元选择器:对于所选元素之前的元素,使用 $prev,对于仅匹配元素查询的元素,请使用 $this,以及其他一些内容。

14

12
"需求"是由 Web 开发者的要求定义的,是否将其包含在规范中取决于其他因素。 - nicodemus13

13

只是一个水平菜单的想法...

HTML的一部分

<div class='list'>
  <div class='item'>
    <a>Link</a>
  </div>
  <div class='parent-background'></div>
  <!-- submenu takes this place -->
</div>

CSS的一部分

/* Hide parent backgrounds... */
.parent-background {
  display: none; }

/* ... and show it when hover on children */
.item:hover + .parent-background {
  display: block;
  position: absolute;
  z-index: 10;
  top: 0;
  width: 100%; }

更新演示和其余代码

另一个例子如何将其与文本输入一起使用-选择父字段集


3
我不太清楚您打算如何将这个概括到一些/许多/大多数父选择器用例中,甚至不确定这个CSS的哪些部分起了什么作用。您能否添加详细的解释? - Nathan Tuggy
2
我没有尝试将其应用于实际场景,这就是为什么我说“不适用于生产环境”。但我认为它只能应用于具有固定项目宽度的二级菜单。关于“这个CSS的哪些部分在做什么” - 这里的.test-sibling实际上是父项的背景(CSS的最后一行)。 - Ilya B.
2
添加说明(jsfiddle的css部分,从“MAIN PART”开始)...而我错了 - 可能有任意数量的子级。 - Ilya B.

11

现在是2019年,CSS嵌套模块的最新草案实际上有类似于这样的东西。引入了@nest at-rules。

3.2. 嵌套At-Rule:@nest

虽然直接嵌套看起来不错,但它有点脆弱。一些有效的嵌套选择器(比如.foo &)被禁止使用,并且以某种方式编辑选择器可能会意外地使规则无效。此外,有些人发现嵌套很难从周围的声明中区分出来。

为了解决所有这些问题,本规范定义了@nest规则,它对如何有效地嵌套样式规则施加了较少的限制。它的语法是:

@nest = @nest <selector> { <declaration-list> }

@nest规则与样式规则的功能相同:它以一个选择器开始,并包含应用于选择器匹配的元素的声明。唯一的区别是,在@nest规则中使用的选择器必须是包含嵌套的选择器,这意味着它在某个地方包含一个嵌套选择器。如果所有单独的复杂选择器都包含嵌套,则选择器列表是包含嵌套的。

(从上面的网址复制并粘贴)。

符合此规范的有效选择器示例:

.foo {
  color: red;
  @nest & > .bar {
    color: blue;
  }
}
/* Equivalent to:
   .foo { color: red; }
   .foo > .bar { color: blue; }
 */

.foo {
  color: red;
  @nest .parent & {
    color: blue;
  }
}
/* Equivalent to:
   .foo { color: red; }
   .parent .foo { color: blue; }
 */

.foo {
  color: red;
  @nest :not(&) {
    color: blue;
  }
}
/* Equivalent to:
   .foo { color: red; }
   :not(.foo) { color: blue; }
 */

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