如何在悬停子元素时为父元素设置样式?

237

我知道并不存在CSS父选择器,但是在没有这样的选择器的情况下,是否有可能在悬停子元素时为父元素设置样式?

举个例子:考虑一个删除按钮,当悬停时会突出显示即将被删除的元素:

<div>
    <p>Lorem ipsum ...</p>
    <button>Delete</button>
</div>

通过纯CSS,当鼠标悬停在按钮上时,如何更改此部分的背景颜色?

3
可能是CSS是否有父级选择器?的重复问题。 - TylerH
可能的解决方案:https://dev59.com/_FkS5IYBdhLWcg3w25sN - Michael Benjamin
没有纯CSS的完美解决方案来实现这个。请参考演示 https://stackoverflow.com/a/77160163 - undefined
8个回答

223
我知道这是一个老问题,但我刚刚成功地完成了它,而不是使用伪子元素(而是伪包装器)。
如果您将父元素设置为没有“pointer-events”,然后将子元素
的“pointer-events”设置为“auto”,它将起作用:) 请注意,标签(例如)无法实现此功能。 还要记得为其他具有自己事件侦听器的子元素设置pointer-events为auto,否则它们将失去单击功能。

div.parent {  
    pointer-events: none;
}

div.child {
    pointer-events: auto;
}

div.parent:hover {
    background: yellow;
}    
<div class="parent">
  parent - you can hover over here and it won't trigger
  <div class="child">hover over the child instead!</div>
</div>

编辑:
正如Shadow Wizard友好地指出的那样:值得一提的是,这在IE10及以下版本中不起作用。(旧版FF和Chrome也是如此,请参见此处


3
值得一提的是,这种方法不能在IE10及以下版本中使用。(旧版的Firefox和Chrome也不行,请参见此处。) - Shadow The Spring Wizard
3
将指针事件设置为“none”也意味着该元素上的事件监听器将不起作用。 - rhazen
1
@rhazen,你说得完全正确。虽然根据我的经验,这种用法通常与单击区域/元素相关联,因此您可以将单击侦听器分配给父级。 - guy_m
如果我有两个层级,父级、子1和子1的子级。我将pointer-events none添加到父级,将pointer-events auto添加到子级。我想悬停在子1上,除了子1的子级。演示在这里:https://codepen.io/lion5893/pen/WNQgyVx - Nam Lê Quý
这是一个赞,兄弟。我成功地在子元素悬停时控制了父元素的CSS,WP。 - Mark Sparrow
如果我有多个子元素,是否有一种方法可以保留指针事件但不触发父元素的悬停效果? - rafalimaz

158

这个问题之前被问过很多次,而典型的简短答案是:无法仅通过 CSS 实现。它体现在名称中:Cascading Style Sheets 只支持在级联方向上进行样式定义,而不支持向上。

但是在大多数情况下,例如给定示例中,仍然可以利用这些级联特性来实现所需效果。考虑这个伪标记:

<parent>
    <sibling></sibling>
    <child></child>
</parent>

关键在于让兄弟元素与父元素大小和位置相同,并对兄弟元素进行样式设置而不是对父元素进行设置。这样看起来就像是对父元素进行了样式设置!

现在,如何对兄弟元素进行样式设置呢?

当子元素被悬停时,父元素也会被悬停,但兄弟元素不会被悬停。同样的情况也适用于兄弟元素。因此,有三种可能的 CSS 选择器路径可用于对兄弟元素进行样式设置:

parent sibling { }
parent sibling:hover { }
parent:hover sibling { }

这些不同的路径可以带来一些不错的可能性。例如,在问题示例上使用这个技巧会得到这个fiddle

div {position: relative}
div:hover {background: salmon}
div p:hover {background: white}
div p {padding-bottom: 26px}
div button {position: absolute; bottom: 0}

父元素样式示例

显然,在大多数情况下,这个技巧依赖于使用绝对定位来使兄弟元素和父元素具有相同的大小,并且仍然让子元素出现在父元素内部。

有时需要使用更合适的选择器路径来选择特定的元素,例如在此 jsfiddle中展示了如何在树形菜单中多次实现该技巧。真的很好用。


1
这对于突出显示很好,但如果您尝试更改字体颜色,它将无效,我是对的吗? - Jahanzeb Khan
1
@JahanzebKhan 更改字体颜色不是问题 - NGLN

33

在2022年:

现在可以仅使用CSS来实现,使用:has伪类和以下表达式:

div:has(button:hover) {}

这里是展示原始主张的片段:

div:has(button:hover) {
  background-color: cyan;      
}
<div>
  <p>Lorem ipsum ...</p>
  <button>Delete</button>
</div>

查看浏览器支持情况这里。写作时,所有主要浏览器都支持它——除了火狐浏览器,它仍然存在有缺陷的试验性实现。


我真的非常希望能在生产中使用它!我真的希望Firefox将来会接受这个。当涉及到仅仅是外观上的悬停效果时,只有Firefox用户会错过这种印象,所以如果你有一些很酷的东西要展示,无论如何最好还是使用它 :-) 但是当它在UI方面更为关键时,你应该避免使用它(目前不幸的是)。 - Hielke
2
根据Bugzilla(https://bugzilla.mozilla.org/show_bug.cgi?id=418039#c62)的说法,他们计划在“今年上半年” [2023] 开始着手处理此问题,因此也许Gecko将最终提供完整支持。 - dakab
哇,你太棒了。ChatGPT甚至不知道在2023年。在CSS和SCSS中,没有直接的方法可以根据子元素的悬停状态选择和更改父元素的样式。CSS级联以自上而下的方式工作,目前没有父选择器或在CSS中向上遍历DOM树的方法。 - ThanHtutZaw
我希望Firefox的实现(即使启用了:has()选择器,目前仍不支持)能尽快支持这一功能,因为这样可以让我在用户悬停在结束屏幕项目上时更轻松地调暗视频播放器。 - undefined
@ChesterFung 目前正在开发中,Mozilla Connect上的一位开发者表示他们的目标是在2023年底之前完全实现该功能。所以如果他们能够达到这个目标,那么很快就会实现。 - undefined
显示剩余2条评论

20

另一种更简单的“替代”方法(针对一个老问题)是将元素放置为兄弟元素,并使用:

相邻兄弟选择器 (+) 或者 通用兄弟选择器 (~)

<div id="parent">
  <!-- control should come before the target... think "cascading" ! -->
  <button id="control">Hover Me!</button>
  <div id="target">I'm hovered too!</div>
</div>
#parent {
  position: relative;
  height: 100px;
}

/* Move button control to bottom. */
#control {
  position: absolute;
  bottom: 0;
}

#control:hover ~ #target {
  background: red;
}

输入图像描述的位置

此处有演示


5
值得注意的是,这仅在 #targets 在 DOM 中跟随 #control 后起作用(即,您无法影响前面的同级元素,只能影响后面的同级元素)。 - Gio

13

在CSS中没有选择已选中子元素的父元素的选择器。

您可以使用JavaScript实现它。


3
当子元素被鼠标悬停时,给它的父元素添加一个名为"hoverClass"的类,当鼠标移开时,从父元素中移除该类。代码示例如下:$(child).hover(function(){$(this).closest(parentSelector).addClass('hoverClass')}, function(){$(this).closest(parentSelector).removeClass('hoverClass')}); - Aamir Afridi
14
@AamirAfridi 这不是纯JS,你需要使用jQuery。 - Ivotje50

11

如先前提到的“没有CSS选择器可以选择已选子元素的父级”。

所以你可以:


这是使用 JavaScript/jQuery 解决方案的示例

在JavaScript方面:

$('#my-id-selector-00').on('mouseover', function(){
  $(this).parent().addClass('is-hover');
}).on('mouseout', function(){
  $(this).parent().removeClass('is-hover');
})

在 CSS 方面,你需要像这样做:

.is-hover {
  background-color: red;
}

3

这个解决方案完全取决于设计,但如果您想在鼠标悬停在子元素时更改父元素的背景色,可以尝试使用 ::after::before 模仿父元素。

<div class="item">
    design <span class="icon-cross">x</span>
</div>

CSS:

.item {
    background: blue;
    border-radius: 10px;
    position: relative;
    z-index: 1;
}
.item span.icon-cross:hover::after {
    background: DodgerBlue;
    border-radius: 10px;
    display: block;
    position: absolute;
    z-index: -1;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    content: "";
}

在这里查看完整的JSFiddle示例


-12

10
Sass并没有为CSS增加更多功能,它只是让编写CSS变得更容易。你可以在Sass中做的任何事情也同样可以在CSS中完成,反之亦然。 - Dastur
3
鉴于变量和mixin,我认为Sass对CSS增加了很多。你可以在CSS中完成所有操作,就像您仍然可以使用纯C编写复杂软件一样。现代语言在不启用以前无法完成的功能的情况下添加了很多功能。Sass和CSS也是如此。 - Cobus Kruger
9
你说得有一定道理,但是你不能进行这样的比较。虽然像C++、C#和JavaScript等编程语言可能是基于C语言的,但它们在运行时并不会变成C语言。Sass在运行之前被转换成了CSS,因此你实际上加载的是CSS样式表而不是Sass样式表。 - Dastur

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