CSS实现:首元素初始阴影,末元素hover移除其阴影、自身hover放大阴影
这确实是CSS选择器的一个经典限制——咱们没法用纯CSS直接选择前面的兄弟元素,不管是相邻兄弟+还是通用兄弟~,都只能选中当前元素之后的节点。不过有几个靠谱的方案能完美实现你的需求,我给你拆解一下:
方案1:用CSS :has() 选择器(推荐,现代浏览器支持)
:has()是CSS新增的“父选择器”能力,它允许我们根据容器内部元素的状态来选中容器,进而修改容器内其他元素的样式,刚好能绕开“向上选兄弟”的限制。
实现代码
首先把两张图片放在一个容器里:
<div class="image-stack"> <img src="your-first-image.jpg" alt="First stacked image" class="stack-img"> <img src="your-second-image.jpg" alt="Second stacked image" class="stack-img"> </div>
然后写CSS:
/* 1. 首元素初始状态带阴影 */ .image-stack .stack-img:first-of-type { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); transition: box-shadow 0.3s ease; /* 加过渡让效果更丝滑 */ } /* 3. 首元素hover时阴影放大 */ .image-stack .stack-img:first-of-type:hover { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25); } /* 2. 末元素hover时,移除首元素的阴影 */ .image-stack:has(.stack-img:last-of-type:hover) .stack-img:first-of-type { box-shadow: none; }
原理
:has(.stack-img:last-of-type:hover)会选中“内部最后一张图片正处于hover状态”的容器,然后我们再选中容器内的首元素,就能实现当末元素hover时修改首元素样式的效果了。目前主流浏览器(Chrome、Firefox 121+、Safari)都支持:has(),如果你的项目不需要兼容特别旧的浏览器,这是最优雅的方案。
方案2:JavaScript实现(兼容旧浏览器)
如果需要兼容不支持:has()的旧浏览器(比如老版Firefox或IE),用JS监听hover事件来手动修改样式是最稳妥的:
实现代码
HTML结构和方案1一样,CSS保留首元素的初始阴影和hover放大效果,然后加JS:
// 获取元素 const lastImage = document.querySelector('.stack-img:last-of-type'); const firstImage = document.querySelector('.stack-img:first-of-type'); // 监听末元素的hover进入事件 lastImage.addEventListener('mouseenter', () => { firstImage.style.boxShadow = 'none'; }); // 监听末元素的hover离开事件,恢复初始阴影 lastImage.addEventListener('mouseleave', () => { firstImage.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)'; });
这种方法兼容性拉满,而且逻辑简单直接,不需要调整DOM结构。
方案3:调整DOM顺序(纯CSS兼容旧浏览器)
如果你坚持想用纯CSS兼容旧浏览器,还可以调整DOM的顺序——把末元素放在首元素前面,然后用CSS定位让视觉上还是首元素在下层、末元素在上层,这样就能用兄弟选择器向下选中首元素了:
实现代码
<div class="image-stack"> <!-- 把末元素放在前面 --> <img src="your-second-image.jpg" alt="Second stacked image" class="stack-img stack-last"> <img src="your-first-image.jpg" alt="First stacked image" class="stack-img stack-first"> </div>
CSS:
.image-stack { position: relative; width: 300px; /* 设一个固定宽度,根据你的图片调整 */ } /* 用定位调整视觉顺序,让首元素在下层 */ .stack-first { position: static; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); transition: box-shadow 0.3s ease; } .stack-last { position: absolute; top: 20px; /* 调整偏移量,模拟堆叠效果 */ left: 20px; } /* 首元素hover时放大阴影 */ .stack-first:hover { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25); } /* 现在末元素在前面,hover它时用~选择后面的首元素 */ .stack-last:hover ~ .stack-first { box-shadow: none; }
这个方案的缺点是需要手动调整定位偏移量,维护起来不如前两个方便,但胜在纯CSS实现,不需要JS。
内容的提问来源于stack exchange,提问作者Ryan Turnbull

