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

React+Hooks点击汉堡图标添加className后Sass样式不生效求助

React Hooks添加className后Sass样式不生效问题解决

问题描述

尝试通过React Hooks实现点击汉堡图标时添加open类,在Sass中针对该类编写样式切换导航栏状态。目前open类已正确添加到元素上,但对应的样式并未生效。本人是Sass和React新手,已尝试调整样式嵌套方式,附上相关代码。

React组件代码

import { useContext, useState } from "react";
import { Link } from "react-router-dom";

import classes from "./styles/MainNavigation.module.css";
import FavoritesContext from "../../store/favorites-context";

function MainNaviagtion() {
  const [isOpen, setOpen] = useState(false);
  const favoriteCtx = useContext(FavoritesContext);

  const mobileMenuHandler = () => {
    setOpen(!isOpen);
  };

  return (
    <header className={classes.header}>
      <div className={classes.logo}>Meet Up Tracker</div>
      <nav>
        <ul id={classes.menu}>
          <li>
            <Link className={classes.link} to="/">
              All Meetups
            </Link>
          </li>
          <li>
            <Link className={classes.link} to="/new-meetups">
              New Meetups
            </Link>
          </li>
          <li>
            <Link className={classes.link} to="/favorites">
              My Favorites
              <span className={classes.badge}>
                {favoriteCtx.totalFavorites}
              </span>
            </Link>
          </li>
        </ul>
      </nav>

      <div id={classes.hamburgerIcon} onClick={mobileMenuHandler} className={isOpen ? 'open' : null}>
        <div className={classes.bar1}></div>
        <div className={classes.bar2}></div>
        <div className={classes.bar3}></div>
        <ul className={classes.mobileMenu}>
          <li>
            <Link className={classes.link} to="/">
              All Meetups
            </Link>
          </li>
          <li>
            <Link className={classes.link} to="/new-meetups">
              New Meetups
            </Link>
          </li>
          <li>
            <Link className={classes.link} to="/favorites">
              My Favorites
              <span className={classes.badge}>
                {favoriteCtx.totalFavorites}
              </span>
            </Link>
          </li>
        </ul>
      </div>
    </header>
  );
}

export default MainNaviagtion;

Sass样式代码

$mobile: 576px;
$tablet: 768px;
$laptop: 992px;
$desktop: 1200px;

.header {
  width: 100%;
  height: 5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background-color: #77002e;
  padding: 0 10%;

  .logo {
    font-size: 30px;
    color: white;
    font-weight: bold;
  }

  .badge {
    background-color: #cc2062;
    color: white;
    border-radius: 12px;
    padding: 0 1rem;
    margin-left: 0.5rem;
  }
}

#hamburgerIcon {
  margin: auto 0;
  display: none;
  cursor: pointer;

  div {
    width: 35px;
    height: 3px;
    background-color: #fff;
    margin: 6px 0;
    transition: 0.4s;
  }
}

.open {
  .bar1 {
    -webkit-transform: rotate(-45deg) translate(-6px, 6px);
    transform: rotate(-45deg) translate(-6px, 6px);
  }

  .bar2 {
    opacity: 0;
  }

  .bar3 {
    -webkit-transform: rotate(45deg) translate(-6px, -8px);
    transform: rotate(45deg) translate(-6px, -8px);
  }

  .mobile-menu {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
  }
}

.mobileMenu {
  display: none;
  position: absolute;
  top: 50px;
  left: 0;
  height: calc(100vh - 50px);
  width: 100%;
}

.header ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: -webkit-inline-box;
  align-items: baseline;
}

.header li {
  margin-left: 3rem;
}

.header a {
  text-decoration: none;
  font-size: 20px;
  color: #fcb8d2;
}

.header a:hover,
.header a:active,
.header a.active {
  color: white;
}

@media (max-width: $tablet) {
  .header {
    .logo {
      font-size: 25px;
    }
    .link {
      display: flex;
      align-items: center;
      font-size: 15px;
      border: 2px solid black;
    }
  }

  .header ul {
    display: -webkit-inline-box;
  }

  .header li {
    margin-left: 1rem;
  }
}

@media (max-width: $mobile) {
  #menu {
    display: none;
  }

  #hamburgerIcon {
    display: block !important;
  }
}

问题原因

  1. CSS Modules类隔离:使用了CSS Modules(从import classes from "./styles/MainNavigation.module.css"可看出),手动添加的open是全局类,而CSS Modules会将局部类名编译成唯一标识,全局类需要用:global()包裹才能匹配到元素。
  2. 选择器命名不匹配:Sass中写的是.mobile-menu,但React组件中用的是classes.mobileMenu,编译后的类名是模块化格式,两者无法对应。
  3. 样式优先级冲突:#hamburgerIcon的ID选择器优先级比.open类选择器高,导致.open下的bar样式被基础样式覆盖。

解决方案

1. 适配CSS Modules的全局类处理

将Sass中的.open选择器嵌套到汉堡图标的类下,并用:global()标记open类:

.hamburgerIcon {
  margin: auto 0;
  display: none;
  cursor: pointer;

  div {
    width: 35px;
    height: 3px;
    background-color: #fff;
    margin: 6px 0;
    transition: 0.4s;
  }

  &:global(.open) {
    .bar1 {
      -webkit-transform: rotate(-45deg) translate(-6px, 6px);
      transform: rotate(-45deg) translate(-6px, 6px);
    }

    .bar2 {
      opacity: 0;
    }

    .bar3 {
      -webkit-transform: rotate(45deg) translate(-6px, -8px);
      transform: rotate(45deg) translate(-6px, -8px);
    }

    .mobileMenu {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: flex-start;
    }
  }
}

2. 修正React组件的className写法

将汉堡图标的ID改为className,并正确拼接open类:

<div 
  className={`${classes.hamburgerIcon} ${isOpen ? 'open' : ''}`}
  onClick={mobileMenuHandler}
>
  <div className={classes.bar1}></div>
  <div className={classes.bar2}></div>
  <div className={classes.bar3}></div>
  <ul className={classes.mobileMenu}>
    {/* 菜单内容 */}
  </ul>
</div>

3. 统一选择器命名与优先级

将Sass中的#hamburgerIcon和#menu改为className,避免ID带来的高优先级冲突:

.menu {
  list-style: none;
  margin: 0;
  padding: 0;
  display: -webkit-inline-box;
  align-items: baseline;
}

@media (max-width: $mobile) {
  .menu {
    display: none;
  }

  .hamburgerIcon {
    display: block !important;
  }
}

同时修改React组件中的ul部分:

<nav>
  <ul className={classes.menu}>
    {/* 菜单内容 */}
  </ul>
</nav>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 20:17:03