Changing the CSS for a React component has effect on all other pages
Asked Answered
A

2

14

I have a React component with the following files:

  • src/components/HomePage/index.js
  • src/components/HomePage/style.scss

The component is very simple:

import React from 'react';
import './style.scss';

const HomePage = () => {
    return (
        <div className="homepage">
            <h1>Landing page</h1>
        </div>
    );
};

export default HomePage;

Within style.scss I am applying a style to all <h1> tags:

h1 {
    color: #f3f3f3;
    font-family: "Cambria";
    font-weight: normal;
    font-size: 2rem;
}

And it works as expected. However, I now see that the h1 style within styles.scss is being applied to every h1 on my site, even on pages that do not use this component.

I am using Gatsby, but it's a React app at heart. My understanding is that React's code-splitting feature would take care of this, that the code from style.scss would only be included in bundles for any page that uses my component.

It's the why that I am asking about. I have two easy fixes:

  • Wrap everything in style.scss in a .homepage wrapper
  • Use CSS modules and rename the file to style.module.scss. When I see people do that they always do `import style from './style.module.scss' - is there a way to have CSS modules without assigning it to an object like that?

Update: Coming back to this question after spending a lot of time with React and I think there's a gap in the market for React styling. CSS modules is syntactically poor in my opinion and having to manually wrap everything in a .home tag to localise it is manual work I don't want to do. Someone should really create a React plugin that automatically does this so that whenever I have a file called Home.js and I import Home.css that all the CSS is automatically restricted to Home.js without me having to do anything special.

Asaasabi answered 25/7, 2020 at 20:31 Comment(3)
check this thread out #47091074Sifuentes
Does this answer your question? How to make React CSS import component-scoped?Polyandry
I understand that CSS modules will simply do the job of wrapping my CSS in a parent tag for me. My question is really about why code splitting does not take care of this? I thought the whole point of code splitting is that JS/CSS wasn't loaded until it was needed.Asaasabi
G
8

If you want to localize CSS rules, then you would have to switch to modular stylesheets (works the same for sass stylesheets).

In your current structure, the component imports non-modular stylesheet and doesn't localize the changes with a unique identifier. Therfore added rules live in a global scope without a unique identifier that would localize them so that only selected components could understand them. That means that they are capable of easily overwriting the same-named rules which were previously established (import order matters here, because it would dictate how the bundler appends the output stylesheet).

So instead of holding component-related rules within ./style.scss file, rename it to ./index.module.scss and then you would utilize it within the component like so:

import React from 'react';
import styles from './index.module.scss';

const HomePage = () => {
    return (
        <div className={style.homepage}>
            <h1 className={style.heading}>Landing page</h1>
        </div>
    );
};

export default HomePage;

and your stylesheet would look like:

.heading {
    color: #f3f3f3;
    font-family: "Cambria";
    font-weight: normal;
    font-size: 2rem;
}

disclaimer:

I've changed the styling convention from selecting elements by their tag, to selecting them by class, because targetting elements by tag is widely considered a bad practice [ref] , but if you want to maintain it, then you would have to provide a parent scope for such a rule (it already exists since the parent <div/> element has an assigned class. In this case the implementation would look like:

import React from 'react';
import styles from './index.module.scss';

const HomePage = () => {
    return (
        <div className={style.homepage}>
            <h1>Landing page</h1>
        </div>
    );
};

export default HomePage;

and styles:

.homepage {
    h1 {
        color: #f3f3f3;
        font-family: "Cambria";
        font-weight: normal;
        font-size: 2rem;
    }
}
Googol answered 25/7, 2020 at 20:46 Comment(3)
Thanks, your second solution is what I have done. I am actually modifying the body tag in this CSS file too so I didn't want to go down the CSS modules route. I guess this just changes my understanding of code-splitting. So am I right in thinking that all CSS for all React components gets compiled into one big CSS bundle loaded on first load? If that's true then I really have no idea how code-splitting works.Asaasabi
That's pretty much correct (there might be deviations however, so don't cite me on this and treat it as a rule of thumb). Modules just prepend the rules with unique identifiers. But as stated within the answer, I think that the root of your problem is providing styles by tag type selectors - best to avoid it.Googol
Just reading here and it looks like React does NOT implement code splitting by default - even flavours like Next.js and Gatsby - and that if you want to achieve what I thought was default behaviour you have to implement lazy loading through React.lazy(). Good to know! I will update my question to include this info. Thanks for your help :)Asaasabi
P
4

You can either go with the easiest way that is mentioned below.

import React from 'react';
import './style.scss';

const HomePage = () => {
    return (
    <div className = "home">
            <div className="homepage">
                <h1>Landing page</h1>
            </div>
    </div>
    );
};

export default HomePage;

You can wrap whole html inside one div of particular component name

CSS:

.home h1 {
    color: #f3f3f3;
    font-family: "Cambria";
    font-weight: normal;
    font-size: 2rem;
}

This is the easiest way. However this is my personal solution because I also face the same issues when I was beginner at react.

Patagium answered 16/10, 2021 at 11:34 Comment(1)
This solution is work great but if we use !important flag element style will overrideAnnecy

© 2022 - 2024 — McMap. All rights reserved.