过去,我经常需要弄清楚如何为容器内的所有元素添加样式,但是 不能 悬停的那个。
此效果需要选择悬停元素的兄弟姐妹。 我曾经为此应用 JavaScript,添加或删除定义正确 CSS 规则的类 mouseenter
和 mouseleave
事件,类似这样:
虽然代码可以解决问题,但我的直觉总是告诉我,必须有一些纯 CSS 方法才能达到相同的结果。 几年前,在为我的公司开发某个滑块时,我想出了一个类似于 Chris Geelhoed 如何重现著名的 Netflix 主页动画 我明白我不再需要 JavaScript 了。
几个月前,我试图在我的公司网站上对基于网格的提要实施相同的方法 - 繁荣 - 由于元素之间的差距,它没有工作!
对我来说幸运的是,它似乎不必保持这种状态,而且我再次不需要 JavaScript。
标记和基础 CSS
让我们通过准备适当的标记开始编码:
.grid
是基于网格的清单
- 和
.grid__child
元素是
我们想与之互动的孩子。
标记如下所示:
样式应如下所示:
.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;
}
这对于在子元素之间没有间隙的容器来说已经足够了:
但是,就我而言,我无法消除这些差距:
当我在瓷砖之间移动鼠标时,所有的子元素都消失了。
无视缝隙
我们可以假设间隙是容器中未被其子项覆盖的部分。 我们不想在每次光标进入容器时运行效果,而是在光标悬停在容器内的一个元素上时运行效果。 那么我们可以忽略光标在间隙上方移动吗?
是的,我们可以,使用 pointer-events: none
在 .grid
容器并将它们带回来 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;
}
只需要额外的 2 行代码,我们就克服了差距问题!
可能的问题
尽管它是一个紧凑的解决方案,但在某些情况下可能需要一些变通方法。
不幸的是,当您希望容器可滚动时(例如,在某种水平滑块中),此技巧将不起作用。 这 pointer-events: none
style 不仅会忽略悬停事件,还会忽略所有其他事件。 在这种情况下,您可以将 .grid
在另一个容器中,像这样:
总结
我强烈鼓励您尝试并尝试为通常预期具有一定复杂性的任务找到一种更简单、更原生的方法。 Web 技术(如 CSS)变得越来越强大,通过使用开箱即用的原生解决方案,您无需维护代码并将其转让给浏览器供应商即可获得出色的结果。
我希望你喜欢这个简短的教程并发现它很有用。 谢谢!