使用CSS或styled-components实现跨行同列元素hover同步样式
问题
能否通过纯CSS实现:当鼠标悬停在某个带特定class的元素上时,所有同class的元素(无论是否存在父子、兄弟层级关系)都同步改变样式?比如悬停任意一行的.col1元素时,所有.col1下的方块都变成黄色背景,其他列同理,且出于性能考虑不想使用JavaScript。
当前代码示例
styled-components 代码
import styled, { css } from 'styled-components'; const WrapperLines = styled.div` display: flex; justify-content: center; align-items: center; flex-direction: column; & > * { :not(:last-child) { margin-bottom: 20px; } } `; const Line = styled.div` display: flex; align-items: center; justify-content: center; border-radius: 10px; background-color: lightgrey; display: flex; width: 100%; `; const Column = styled.div` margin: 20px; `; const Div = styled.div` position: relative; border-radius: 15px; display: flex; align-items: center; justify-content: center; height: 100px; width: 100px; background: red; ${(props) => css` ${props.primary}:hover & { background: yellow; } `}; `;
JSX 代码
<WrapperLines> <Line className="line1"> <Column className="col1"> <Div primary={'.col1'}> Line 1 Col 1 </Div> </Column> <Column className="col2"> <Div primary={'.col2'}> Line 1 Col 2 </Div> </Column> <Column className="col3"> <Div primary={'.col3'}> Line 1 Col 3 </Div> </Column> </Line> <Line className="line2"> <Column className="col1"> <Div primary={'.col1'}> Line 2 Col 1 </Div> </Column> <Column className="col2"> <Div primary={'.col2'}> Line 2 Col 1 </Div> </Column> <Column className="col3"> <Div primary={'.col3'}> Line 2 Col 1 </Div> </Column> </Line> </WrapperLines>
解决方案
可以通过父容器级别的CSS选择器实现需求,核心是利用:has()选择器监听父容器内的hover状态,同时选中所有同class的目标元素,无需JavaScript。
修改后的代码
styled-components 代码
import styled from 'styled-components'; const WrapperLines = styled.div` display: flex; justify-content: center; align-items: center; flex-direction: column; & > * { :not(:last-child) { margin-bottom: 20px; } } // 核心逻辑:当任意.colX被hover时,所有同class下的Div同步变色 &:has(.col1:hover) .col1 ${props => props.DivComponent}, &:has(.col2:hover) .col2 ${props => props.DivComponent}, &:has(.col3:hover) .col3 ${props => props.DivComponent} { background: yellow; } `; const Line = styled.div` display: flex; align-items: center; justify-content: center; border-radius: 10px; background-color: lightgrey; width: 100%; `; const Column = styled.div` margin: 20px; `; const Div = styled.div` position: relative; border-radius: 15px; display: flex; align-items: center; justify-content: center; height: 100px; width: 100px; background: red; transition: background 0.2s; // 可选:添加平滑过渡动画 `;
JSX 代码
<WrapperLines DivComponent={Div}> <Line className="line1"> <Column className="col1"> <Div> Line 1 Col 1 </Div> </Column> <Column className="col2"> <Div> Line 1 Col 2 </Div> </Column> <Column className="col3"> <Div> Line 1 Col 3 </Div> </Column> </Line> <Line className="line2"> <Column className="col1"> <Div> Line 2 Col 1 </Div> </Column> <Column className="col2"> <Div> Line 2 Col 2 </Div> </Column> <Column className="col3"> <Div> Line 2 Col 3 </Div> </Column> </Line> </WrapperLines>
原理说明
:has()选择器:这是CSS的原生特性,用于检测父容器是否包含满足条件的子元素。这里通过WrapperLines:has(.col1:hover)判断是否有.col1元素被悬停。- 批量选中同class元素:当检测到hover状态后,通过
.col1 ${props => props.DivComponent}选中所有.col1下的Div组件,统一修改样式。 - 兼容性提示:
:has()目前已被现代浏览器支持(Chrome 105+、Firefox 121+等),如果需要兼容旧浏览器,可考虑使用CSS变量结合兄弟选择器的方案,但复杂度会更高。
内容的提问来源于stack exchange,提问作者eldala07
相关产品推荐
相关产品推荐

