react route how to import local scss file only apply to one js file?

Viewed 1428

In one React app with React Router, for each route component, I would like to have one local scss file only apply to this file.

For below example, about.js imported about.scss, what I want to have is: about.scss override the global style in app.scss only in about.js. However, it overrode everything in the app

app.js - imported app.scss which I prefer as a global style

import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import "./app.scss";  // global scss
import About from "./about";

export default function App() {
  return (
    <>
      <h1>question about scss in react route</h1>
      <Router>
        <div>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
          </ul>
          <hr />
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
        </div>
      </Router>
    </>
  );
}
function Home() {
  return (
    <div>
      <h3 className={"myMargin"}>home</h3>
    </div>
  );
}

app.scss (the global style)

h3.myMargin {
  margin: 10px
}

about.js

import React from "react";
import "./about.scss";

export default function About() {
  return (
    <div>
      <h3 className={"myMargin"}>About</h3>
    </div>
  );
}

about.scss (I want to be a local style, however, it applied to everywhere in the app)

h3.myMargin {
  margin: 100px
}

Any suggestion how to structure my style code?

1 Answers

The beauty (and caveat) of CSS is in the first C of its acronym —which stands for cascading— meaning there is a cascade of (fairly predictable) rules to follow.

In this case about.scss being imported later, will override your h3 from app no matter what.

1) Use a container:

import React from "react";
import "./about.scss";

export default function About() {
  return (
    <div className='about-page'>
      <h3 className="myMargin">About</h3> // note: no need for {"myMargin"}
    </div>
  );
}

// about.scss
.about-page {
  h3.myMargin {
    margin: 10px
  }
}

2) Using CSS Modules:

Another one is to use CSS Modules, enabled by default if you use a fairly recent version of create-react-app:

import React from "react";
import styles from "./About.module.scss";

export default function About() {
  return (
    <div>
      <h3 className={styles.myMargin}>About</h3>
    </div>
  );
}

// About.module.scss
.myMargin {
  margin: 10px
}

This will generate a unique className, so your processed code will look something like this:

<div>
  <h3 class='About_myMargin_mVxOd>About</h3>
</div>

The random hash (mVxOd as an example) will allow your styles to not overwrite each other.

There are pros and cons of both methods, the biggest problem when using regular CSS/SCSS imports is that you are at the mercy of the rules of CSS: if you accidentally create a global class .error then the rules will cascade to any component and its hard to keep track. Importing Bootstrap for example, will overwrite a whole lot of CSS names that you have no idea about (until you realize your CSS is off).

Another problem is that, if a said route doesn't import a CSS file, but later on following a different path of routes does import the file, you could end up with different styling. This has happened to us a few times, so it's a must to be extra careful especially in bigger teams.

CSS Modules has a few big drawbacks, first one being that you cannot directly override a style from another CSS file just by overriding its CSS class (because of said hash). Second, you cannot access nested CSS selectors allowed by SASS.

I personally have used both for production and personal projects and both are equally great -- when used carefully.

There is a third popular option called Styled Components. It's personally not my preferred and I haven't used it much, but you can learn more abouut it on its official page. It looks like this:

const Title = styled.h3`
  margin: 10px;
`

render() {
  return <Title>About</Title> // creates an h3 tag
}

One last one, being CSS in JS which I haven't used enough either.

Related