You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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%);
}

问题原因

  1. CSS兄弟选择器限制:~选择器仅能选中当前元素之后的同级元素,box2在DOM结构中位于box1之后,所以box1:hover ~ .box2能生效,但box1在box2之前,box2:hover ~ .box1无法匹配到任何元素。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:43:13