过去,我经常需要想办法如何为容器内的所有元素添加样式,但不包括悬停的那个元素。

此效果需要选择悬停元素的兄弟元素。我过去会使用 JavaScript 来实现这一点,在mouseenter
和mouseleave
事件中添加或删除定义适当 CSS 规则的类,类似于这样
尽管这段代码可以解决问题,但我总有一种感觉,一定有某种纯 CSS 的方法可以达到相同的效果。几年前,在为公司开发某个滑块时,我想出了一个类似于Chris Geelhoed 如何在 CSS 中重现著名的 Netflix 首页动画 的解决方案,我意识到我不再需要 JavaScript 了。
几个月前,我试图在我的公司网站上基于网格的 Feed 中实现相同的方法,结果——砰的一声——由于元素之间的间隙,它不起作用了!
幸运的是,事实证明它不必一直这样,我再次不需要 JavaScript 了。
标记和基础 CSS
让我们通过准备适当的标记开始编码
.grid
是一个基于网格的<ul>
列表;- 而
.grid__child
元素是我们想要交互的<li>
子元素。
标记如下所示
<ul class="grid">
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
</ul>
样式应如下所示
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, 15rem);
grid-gap: 1rem;
}
.grid__child {
background: rgba(0, 0, 0, .1);
border-radius: .5rem;
aspect-ratio: 1/1;
}
此示例代码将创建三个列表项,在网格中占据三列。
CSS 选择器的强大功能
现在,让我们添加一些交互性。我最初采用的方法基于两个步骤
- 将鼠标悬停在容器上应更改所有内部元素的样式……
- ……除了当前鼠标悬停的元素。
让我们从在光标悬停在容器上时获取每个子元素开始
.grid:hover .grid__child {
/* ... */
}
其次,让我们排除当前悬停的项目,并降低任何其他子元素的opacity
.grid:hover .grid__child:not(:hover) {
opacity: 0.3;
}
对于子元素之间没有间隙的容器,这将绰绰有余

但是,在我的情况下,我无法移除这些间隙

当我将鼠标在块之间移动时,所有子元素都淡出了。
忽略间隙
我们可以假设间隙是容器中未被其子元素覆盖的部分。我们不希望每次光标进入容器时都运行该效果,而是在它悬停在内部的某个元素上时运行。那么,我们能否忽略光标在间隙上方的移动呢?
可以,我们可以使用.grid
容器上的pointer-events: none
,并在其子元素上使用pointer-events: auto
将其恢复。
.grid {
/* ... */
pointer-events: none;
}
/* ... */
.grid__child {
/* ... */
pointer-events: auto;
}
让我们在不透明度上添加一些很酷的过渡,我们就得到了一个现成的组件
当我们添加更多块并创建二维布局时,它可能看起来更酷
最终 CSS 如下所示
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, 15rem);
grid-gap: 3rem;
pointer-events: none;
}
.grid:hover .grid__child:not(:hover) {
opacity: 0.3;
}
.grid__child {
background: rgba(0, 0, 0, .1);
border-radius: .5rem;
aspect-ratio: 1/1;
pointer-events: auto;
transition: opacity 300ms;
}
仅用两行额外的代码,我们就克服了间隙问题!
可能存在的问题
尽管这是一个简洁的解决方案,但在某些情况下,它可能需要一些变通方法。
不幸的是,当您希望容器可滚动时,此技巧将不起作用,例如,在某种水平滑块中。pointer-events: none
样式不仅会忽略悬停事件,还会忽略所有其他事件。在这种情况下,您可以将.grid
包装到另一个容器中,如下所示
<div class="container">
<ul class="grid">
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
<li class="grid__child"></li>
</ul>
</div>
总结
我强烈建议您进行实验,并尝试为通常需要一定复杂程度的任务找到更简单、更原生方法。像 CSS 这样的 Web 技术正变得越来越强大,通过使用开箱即用的原生解决方案,您可以在无需维护代码并将其交给浏览器供应商的情况下获得出色的效果。
希望您喜欢这个简短的教程,并觉得它有用。谢谢!
作者选择了科技教育基金作为“为捐赠写作”计划的一部分接收捐款。
在Twitter 上,KonstantinRouda (Konrud) 建议使用
:has()
来避免使用pointer-events: none
。酷,感谢在这里分享!
使用 visibility 和更好的浏览器兼容性实现更好的技巧 -> https://jsbin.com/hinikinete/2/edit?html,css,output