How to apply global styles with CSS modules in a react app?

后端 未结 5 764
孤独总比滥情好
孤独总比滥情好 2020-12-23 15:57

I\'m currently using CSS Modules with React for my styling. So each of my components is importing in it\'s component specific css file, like so:

import React         


        
相关标签:
5条回答
  • 2020-12-23 16:20

    Solution 1 :

    Import global styles in starting point of reactapp.
    where the whole react app has been wrapped in a root component .
    it can be index.js or app.js or index.html

    Solution 2 :

    use scss and create main.scss file and import all other specifically needed custom scss files in main.scss

    0 讨论(0)
  • 2020-12-23 16:23

    This can be done by simply adding:

    require('./App.css');
    

    (thanks @elmeister who correctly answered this question.)

    0 讨论(0)
  • 2020-12-23 16:27

    The only way I found for importing styles globally, but only for a specific route is adding:

    <style dangerouslySetInnerHTML={{__html: `
      body { max-width: 100% }
    `}} />
    

    inside the return of render method.

    Otherwise, the style tag would be added to the <head>, and the styles would be applied for all next routes.

    From https://medium.learnreact.com/the-style-tag-and-react-24d6dd3ca974

    Maybe the styles could be imported as a string from a file to have the code more organized.

    0 讨论(0)
  • 2020-12-23 16:33

    Since you're using the ES6 import syntax you may use the same syntax to import your stylesheet

    import './App.css'
    

    Also, you can wrap your class with :global to switch to the global scope (this mean CSS Module won't modulify it, eg: adding a random id next to it)

    :global(.myclass) {
      background-color: red;
    }
    
    0 讨论(0)
  • 2020-12-23 16:46

    I had encountered the same problem and found the following ways to address the issue, you may choose what applies to you best

    1. Define two sets of rules in your webpack config for parsing css/less files.
      • The first rule should be to include all global styles, assuming it's kept in /styles/ or similar directory.
      • The second rule is to process all locally scoped css styles, these should ideally be next to their components.
      • You can do this by using the include and exclude option while defining a rule
      • or by enforcing a naming convention and writing rule accordingly, for example all css modules will be [name].module.css and your test would check for /.module.(less|css)$/ and parse it.

    A sample is given below:

          // exclude all global styles for css modules
          {
            test: /\.(less|css)$/,
            exclude: path.resolve(__dirname, './src/styles'),
            use: [
              {
                loader: CssExtractPlugin.loader,
                options: { hot: is_dev, reloadAll: is_dev }
              },
              {
                loader: "css-loader",
                options: { 
                    modules: { 
                        localIdentName: '[local]___[hash:base64:5]'
                    }
                }
              },
              "postcss-loader",
              "less-loader"
            ]
          },
          // process global styles without css modules
         {
            test: /\.(less|css)$/,
            include: path.resolve(__dirname, './src/styles'),
            use: [
              {
                loader: CssExtractPlugin.loader,
                options: { hot: is_dev, reloadAll: is_dev }
              },
              "css-loader",
              "postcss-loader",
              "less-loader"
            ]
          }
    
    1. Use :local and :global while writing css/less. If css modules is enabled it will default to local mode, you can specify the mode in options as below:
              {
                loader: "css-loader",
                options: { 
                    modules: { 
                        localIdentName: '[local]___[hash:base64:5]', 
                        mode: 'global',
                    }
                }
              },
    

    If you are defining mode as global then all your included css classes will not be replaced with hashed names, instead only the ones you specify as :local will be given unique names. For example:

    /* this will remain as is */
    .header {
       color: blue;
    }
    
    :local {
      /* this will become something like item_xSH2sa */
      .item {
       color: yellow;
      }
    }
    
    
    1. Define a function which checks your file to decide if it's css module or global, done using getLocalIdent option. This is the method that I'm currently using in my setup. This also requires your files to have some naming convention, [name].module.less for css modules and [name].less for regular files. See example below:
    // regex to test for modules, loaderUtils is part of webpack dependencies
    const cssModuleRegex = new RegExp(/\.module\.(less|css)$/);
    const loaderUtils = require("loader-utils");
    
    // inside webpack rules
          {
            test: /\.(less|css)$/,
            use: [
              {
                loader: CssExtractPlugin.loader,
                options: { hot: is_dev, reloadAll: is_dev }
              },
              {
                loader: "css-loader",
                options: { 
                    modules: { 
                        localIdentName: '[local]___[hash:base64:5]', 
                        getLocalIdent: getLocalIdent
                    }
                }
              },
              "postcss-loader",
              "less-loader"
            ]
          }
    
    // this is a copy of the default function, modified slightly to achieve our goal
    function getLocalIdent(loaderContext, localIdentName, localName, options) {
    
        // return local name if it's a global css file
        if (!cssModuleRegex.test(loaderContext.resourcePath)) {
            return localName;
        }
    
        if (!options.context) {
          // eslint-disable-next-line no-param-reassign
          options.context = loaderContext.rootContext;
        }
    
        const request = path
          .relative(options.context, loaderContext.resourcePath)
          .replace(/\\/g, '/');
    
        // eslint-disable-next-line no-param-reassign
        options.content = `${options.hashPrefix + request}+${localName}`;
    
        // eslint-disable-next-line no-param-reassign
        localIdentName = localIdentName.replace(/\[local\]/gi, localName);
    
        const hash = loaderUtils.interpolateName(
          loaderContext,
          localIdentName,
          options
        );
    
        return hash
          .replace(new RegExp('[^a-zA-Z0-9\\-_\u00A0-\uFFFF]', 'g'), '-')
          .replace(/^((-?[0-9])|--)/, '_$1');
      }
    
    
    0 讨论(0)
提交回复
热议问题