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

CSS实现可滚动div:React购物车商品列表滚动失效问题

React购物车商品区纵向滚动失效修复

问题现象

  • 需求:不改动现有父子组件DOM结构,仅为左侧承载购物商品的容器添加纵向滚动效果
  • 异常:给目标元素设置overflow-y: scroll属性后,页面仅渲染出滚动条样式,即使手动设置任意高度值也无法触发滚动交互,未定位到问题根源
  • 问题界面:
    购物车模态框界面

关联代码

父组件CartModal实现

const CartModal = () => {
  const { totalPrice, totalAmount } = useSelector((state) => state.cart);

  return (
    <div className={classes["cart-modal"]}>
      <div className={classes["cart-modal__navbar"]}></div>
      <div className={classes["cart-modal__body"]}>
        <div className={classes["body__left-side"]}>
          <h1>ORDERS</h1>
          <CartModalFoodList />
        </div>
        <div className={classes["body__right-side"]}>
          <div>
            <img src={BigCart} />
          </div>
          <div>
            <h2>Total price:</h2>
            <h2>{totalPrice}$</h2>
          </div>
          <div>
            <h2>Total amount:</h2>
            <h2>{totalAmount}</h2>
          </div>
        </div>
      </div>
    </div>
  );
};

父组件样式代码

.cart-modal {
  z-index: 100;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 65vw;
  height: 75vh;
  background-color: var(--main-bg-color);
  border-radius: 10px;
  box-shadow: 1px 2px 5px;
  overflow: hidden;
}

.cart-modal__navbar {
  width: 100%;
  height: 15vh;
  background: radial-gradient(
    50% 50% at 50% 50%,
    var(--gradient-color-one) 0%,
    var(--gradient-color-two) 100%
  );
}

.cart-modal__body {
  display: flex;
  height: 100%;
}

.body__left-side {
  height: 100%;
  width: 55%;
  background-color: white;
  padding: 0 3.5%;
}

.body__left-side h1 {
  color: var(--strong-yellow);
  text-align: center;
  border-bottom: 1px solid var(--weak-yellow);
  padding-bottom: 2%;
}

.body__right-side {
  width: 45%;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.body__right-side div:first-child {
  height: 50%;
  width: 100%;
}

.body__right-side div:first-child img {
  height: 100%;
  width: 100%;
}

.body__right-side *:not(:first-child) {
  display: flex;
  justify-content: space-around;
}

.body__right-side *:not(:first-child) h2 {
  font-size: 2vw;
  margin: 2.5% 0;
}

左侧商品列表MenuList组件实现

const MenuList = (props) => {
  const page = props.page;
  const dispatch = useDispatch();
  const foodArray = props.foodList;

  const navigate = useNavigate();
  const location = useLocation();
  const params = useParams();

  const [foodList, setFoodList] = useState([]);

  useEffect(() => {
    setFoodList(formatArray(foodArray));
  }, [foodArray]);

  const queryPrams = new URLSearchParams(location.search);
  const sort = queryPrams.get("sort");

  const onNextPageHandler = () => {
    dispatch(uiSliceActions.updatePage("forward"));
  };
  const onPreviousPageHandler = () => {
    dispatch(uiSliceActions.updatePage("backward"));
  };
  const onSortPageHandler = () => {
    navigate(
      `/menu/${params.foodId ? params.foodId + "/" : ""}?sort=${
        sort === "asc" ? "desc" : "asc"
      }`
    );
    let foodListPart = foodList[page];
    let foodListSort = foodList;

    const sortFoodList = (sort) => {
      foodListPart = foodListPart.sort((a, b) =>
        sort === "asc" ? a.foodPrice - b.foodPrice : b.foodPrice - a.foodPrice
      );
      foodListSort[page] = foodListPart;
      setFoodList(foodListSort);
    };
    sort === "asc" ? sortFoodList("asc") : sortFoodList("desc");
  };

  return (
    <Fragment>
      <div className={classes["menu-list"]}>
        {foodList[page]
          ? foodList[page].map((foodObj) => (
              <MenuItem key={foodObj.id} foodObj={foodObj} />
            ))
          : ""}
      </div>
      <div className={classes["menu-list__buttons"]}>
        {page >= 1 && (
          <Button type="button" onClick={onPreviousPageHandler}>
            Page {page}
          </Button>
        )}
        <Button
          type="button"
          onClick={onSortPageHandler}
          className={classes["sort-button"]}
        >
          {sort === "asc" ? `Descending` : `Ascending`}
        </Button>
        <Button type="button" onClick={onNextPageHandler}>
          Page {page + 2}
        </Button>
      </div>
    </Fragment>
  );
};

商品列表容器现有样式

.menu-list {
  overflow-y: scroll;
}

问题根因

滚动不生效的核心是设置了滚动属性的元素没有被限制高度,会被内部内容完全撑开,不存在内容溢出容器的场景,具体问题点:

  1. 高度计算错误:.cart-modal__body设置height: 100%是相对于父容器.cart-modal的75vh高度计算,但它的上一个兄弟节点.cart-modal__navbar已经占据了15vh高度,最终body区域实际总高度超出模态框范围,只是被父级的overflow: hidden裁剪没有显示溢出
  2. 滚动容器无高度约束:.menu-list没有设置固定高度/弹性分配高度,高度完全由内部商品项撑开,即使设置overflow-y: scroll也没有滚动的空间
  3. 存在属性拼写错误:代码中书写的overwflow-y是笔误,正确属性名为overflow-y

修复方案(无需改动组件DOM结构)

从父层到子层修正高度计算逻辑,给滚动容器分配明确的受限高度即可:

  1. 修正body区域高度,减去顶部导航栏占据的高度:
.cart-modal__body {
  display: flex;
  height: calc(100% - 15vh);
}
  1. 给左侧容器开启纵向弹性布局,让内部子元素可以自动分配剩余空间,避免内容撑开容器:
.body__left-side {
  height: 100%;
  width: 55%;
  background-color: white;
  padding: 0 3.5%;
  display: flex;
  flex-direction: column;
}
  1. 给商品列表容器设置弹性占满剩余空间,开启自动滚动:
.menu-list {
  flex: 1;
  overflow-y: auto;
}

修改后商品列表的高度会被自动限制在左侧区域扣除标题、底部按钮后的剩余空间内,商品内容超出容器高度时即可正常纵向滚动,全程不需要调整现有组件的DOM结构。


内容的提问来源于stack exchange,提问作者Nijaz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 21:30:57