Home > Enterprise >  How do i refer the className when having a nested scss ? nextjs reactjs
How do i refer the className when having a nested scss ? nextjs reactjs

Time:06-07

I have a navbar with a hamburger button and i want to change the style (the bar color and the hamburger button style) on tap. I mention that i've tried using &:active, &.activeBar on the scss file. For some reason the background color doesn t change and the hamburger button doesn't turn into an X

This is my SCSS file:

.topbar {
  width: 100%;
  background-color: $secondaryColor;
  color: $mainColor;
  height: 70px;
  position: fixed;
  top: 0;
  z-index: 3;
  transition: all 1s ease;
  overflow: hidden;

  .wrapper {
    padding: 10px 30px; 
    display: flex; 
    align-items: center; 
    justify-content: space-between; 
  }

  .left {
    display: flex;
    align-items: center;
    margin: 10;
    .itemContainer {
      display: flex;
      align-items: center;

      .icon {
        font-size: 36px;
        margin-right: 5px;
        &:hover {
          color: blue;
        }
      }
      span {
        font-size: 15px;
        font-weight: 700;
      }
    }
    .logo {
      font-size: 40px;
      font-weight: 700;
      text-decoration: none;
      color: inherit;
      margin-right: 40px;
    }
  }

  .right {
    .hamburger {
      width: 32px;
      height: 25px;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      span {
        width: 100%;
        height: 3px;
        background-color: $mainColor;
        transform-origin: left;
        transition: all 0.5s ease;
      }
    }
  }

  &.activeBar {
    background-color: $mainColor;
    color: $secondaryColor;
    .hamburger span {
      &:first-child {
        background-color: $secondaryColor;
        transform: rotate(45deg);
      }
      &:nth-child(2) {
        opacity: 0;
      }
      &:last-child {
        background-color: $secondaryColor;
        transform: rotate(-45deg);
      }
    }
  }
}

And this is where i try to change the classname in my js file:

import React from 'react';
import styles from './topbar.module.scss';
import { Facebook } from '@material-ui/icons';

const Topbar = ({ open, toggle }) => {
  function menuToggled() {
    toggle(!open);
    console.log('menuToggled', open);
  }
  return (
    <div className={`${styles.topbar} ${open ? 'active' : ''}`}>
      <div className={styles.wrapper}>
        <div className={styles.left}>
          <a href='#slider' className={styles.logo}>
            Muntenia cu gust
          </a>
          <div className={styles.itemContainer}>
            <Facebook
              className={styles.icon}
              onClick={() => window.open('https://stackoverflow.com/')}
            />
          </div>
        </div>
        <div className={styles.right}>
          <div className={styles.hamburger} onClick={menuToggled}>
            <span className={styles.line1}></span>
            <span className={styles.line2}></span>
            <span className={styles.line3}></span>
          </div>
        </div>
      </div>
    </div>
  );
};

export default Topbar;

CodePudding user response:

In your code, you're adding active as a class in the "global" scope. By default with css-modules, all classes are output in "local" scope. So your .topbar class, after compilation, would look something like: .Topbar_topbar__abc12 ("abc12" would be a hash).

So, the .active class is also being compiled to local scope, looking something like: .Topbar_active_def34

In your markup, you're toggling the .active class as a string rather than as styles.active. So, on output, you're expecting your "active" class to be .Topbar_topbar__abc12.active when in actuality, your stylesheet is declaring .Topbar_topbar_abc12.Topbar_active_def32 as the "active" class.

By declaring .active as being in the global scope, the output would then be as expected. Try adding the :global flag to your stylesheet:

...
  &:global(.active) {
    background-color: $mainColor;
    color: $secondaryColor;
    .hamburger span {
      &:first-child {
        background-color: $secondaryColor;
        transform: rotate(45deg);
      }
      &:nth-child(2) {
        opacity: 0;
      }
      &:last-child {
        background-color: $secondaryColor;
        transform: rotate(-45deg);
      }
    }
  }
...

CodePudding user response:

use classnames package (https://www.npmjs.com/package/classnames) to combine classes that are on the same element, the rest is handled the same as in vanilla html/css/js In your code you use active it also should come from styles and be combined using:

classnames('styles.ElementClassName', active && styles.active)

CodePudding user response:

Adding the active selector on the regular .hamburger class should trigger on touch. Also the classname in you scss is activeBar but in your react app is only active.

&.clicked {
background-color: $mainColor;
color: $secondaryColor;
.hamburger span {
  &:first-child {
    background-color: $secondaryColor;
    transform: rotate(45deg);
  }
  &:nth-child(2) {
    opacity: 0;
  }
  &:last-child {
    background-color: $secondaryColor;
    transform: rotate(-45deg);
  }

 }
   }

If you want to change the topBar also then you'll need to change your TopBar component a bit

import React, { useState } from 'react';
import styles from './topbar.module.scss';
import { Facebook } from '@material-ui/icons';

const Topbar = ({ open, toggle }) => {
    const [isClicked, setIsClicked] = useState(false);
  function menuToggled() {
    toggle(!open);
    console.log('menuToggled', open);
  }
  return (
    <div className={`${styles.topbar} ${open ? 'active' : ''} ${ isClicked && ' clicked'}`}>
      <div className={styles.wrapper}>
        <div className={styles.left}>
          <a href='#slider' className={styles.logo}>
            Muntenia cu gust
          </a>
          <div className={styles.itemContainer}>
            <Facebook
              className={styles.icon}
              onClick={() => window.open('https://stackoverflow.com/')}
            />
          </div>
        </div>
        <div className={styles.right}>
          <div className={styles.hamburger} onClick={menuToggled} onTouchStart={(e) => setIsClicked(true)}>
            <span className={styles.line1}></span>
            <span className={styles.line2}></span>
            <span className={styles.line3}></span>
          </div>
        </div>
      </div>
    </div>
  );
};
  • Related