React组件中Rivian风格双盒子悬停动画异常排查
问题:双盒子悬停交互动画异常
克隆Rivian官网时实现了双盒子组件,左侧盒子(box1)悬停时右侧盒子(box2)能向右收缩让位,动画正常;但右侧盒子(box2)悬停时,左侧盒子(box1)无法向左收缩让位,动画失效。
现有代码
Configurator.jsx
import "./configurator.css"; const Configurator = () => { return ( <div style={{ width: "100%", backgroundColor: "#fff", height: "90vh" }}> <div className="grid grid-cols-2 gap-7 pt-20 " style={{ height: "30vh", marginBottom: "5vh" }} > <div className="flex justify-end"> <h1 className="text-5xl"> Vehicles made for the <br /> planet </h1> </div> <div> <h3 className="text-xl"> Whether taking families on new adventures or <br /> electrifying fleets at scale, our vehicles all share a <br /> common goal — preserving the natural world for <br /> generations to come. </h3> </div> </div> <div className="grid grid-cols-2 gap-7 px-0 border-2 mx-4 overflow-hidden" style={{ height: "40vh", marginBottom: "5vh" }} > <div className="h-30 w-full relative box1" style={{ backgroundColor: "#f2f2f2" }} > <div className="h-full w-full box-content"> <h3 className="absolute top-4 left-4"> R1T | Up to 410 miles of range </h3> <div className="absolute top-1/5 left-20 right-10 flex justify-center"> <img className="aspect-[4/3]" src="src\assets\asset 2.png" alt="" /> </div> <div className="absolute bottom-0 flex justify-end w-full pb-6 px-6 gap-4"> <button className="border-2 border-black rounded-3xl py-3 px-8"> Configure </button> <button className="text-white border-2 border-black rounded-3xl bg-black py-3 px-6"> Shop Available </button> </div> </div> </div> <div className="h-30 w-full relative box2" style={{ backgroundColor: "#f2f2f2" }} > <div className="h-full w-full box-content"> <h3 className="absolute top-4 left-4"> R1T | Up to 410 miles of range </h3> <div className="absolute top-1/5 left-20 right-10 flex justify-center"> <img className="aspect-[4/3]" src="src\assets\asset 2.png" alt="" /> </div> <div className="absolute bottom-0 flex justify-end w-full pb-6 px-6 gap-4"> <button className="border-2 border-black rounded-3xl py-3 px-8"> Configure </button> <button className="text-white border-2 border-black rounded-3xl bg-black py-3 px-6"> Shop Available </button> </div> </div> </div> </div> </div> ); }; export default Configurator;
configurator.css
.container { display: flex; height: 80vh; width: 100%; } .box1, .box2 { transition: transform 0.5s ease-in-out; } .box1:hover, .box2:hover { transform: scaleX(1.1); } .box1 .box-content { transition: transform 0.5s ease-in-out; } .box2 .box-content { transition: transform 0.5s ease-in-out; } .box1:hover .box-content { transform: scaleX(0.9091); } .box1:hover ~ .box2 { transform: translateX(3%); } .box2:hover .box-content { transform: scaleX(0.9091); } .box2:hover ~ .box1 { transform: translateX(3%); }
问题原因
- CSS兄弟选择器限制:
~选择器仅能选中当前元素之后的同级元素,box2在DOM结构中位于box1之后,所以box1:hover ~ .box2能生效,但box1在box2之前,box2:hover ~ .box1无法匹配到任何元素。 - Grid布局局限性:Grid的列宽是固定分配的,hover时的transform易被布局规则限制,不如flex布局灵活。
解决方案
修改后的代码
Configurator.jsx
仅修改双盒子的父容器布局,将grid grid-cols-2替换为flex gap-7:
// 其他代码不变 <div className="flex gap-7 px-0 border-2 mx-4 overflow-hidden" style={{ height: "40vh", marginBottom: "5vh" }} > // 其他代码不变
configurator.css
.box1, .box2 { flex: 1; transition: transform 0.5s ease-in-out; position: relative; } .box1:hover, .box2:hover { transform: scaleX(1.1); z-index: 1; } .box-content { height: 100%; width: 100%; transition: transform 0.5s ease-in-out; } .box1:hover .box-content, .box2:hover .box-content { transform: scaleX(0.9091); } /* box1悬停时,box2向右位移 */ .box1:hover + .box2 { transform: translateX(3%); } /* box2悬停时,利用:has选择器控制box1向左位移 */ .flex:has(.box2:hover) .box1 { transform: translateX(-3%); }
说明
- 使用
flex:1让两个盒子平分宽度,flex布局更适配动态位移场景。 :has()选择器检测父容器内的hover状态,解决了兄弟选择器只能选后续元素的问题;若需兼容旧浏览器,可通过JavaScript监听hover事件添加/移除类名实现。- 给hover的盒子加
z-index:1,避免缩放时被另一个盒子遮挡。
内容的提问来源于stack exchange,提问作者DOMINATOR X
相关产品推荐
相关产品推荐

