如何在 React 应用程序中使用 CSS 模块应用全局样式?
How to apply global styles with CSS modules in a react app?
我目前正在使用 CSS 模块和 React 来设计我的样式。所以我的每个组件都在其组件特定的 css 文件中导入,如下所示:
import React from 'react';
import styles from './App.css';
const example = () => (
<div className={styles.content}>
Hello World!
</div>
);
export default example;
这在为单个组件设置样式时效果很好,但我如何应用非组件的全局样式(html、body、header 标签、div 等)具体的?
这可以通过简单地添加来完成:
require('./App.css');
(感谢@elmeister 正确回答了这个问题。)
由于您使用的是 ES6 导入语法,因此您可以使用相同的语法导入样式表
import './App.css'
此外,你可以用 :global
包装你的 class 以切换到全局范围(这意味着 CSS 模块不会修改它,例如:接下来添加一个随机 ID到它)
:global(.myclass) {
background-color: red;
}
我找到的全局导入样式的唯一方法,但仅针对特定路径是添加:
<style dangerouslySetInnerHTML={{__html: `
body { max-width: 100% }
`}} />
在 render
方法的 return 中。
否则,style
标签将添加到 <head>
,并且样式将应用于所有后续路线。
来自https://medium.learnreact.com/the-style-tag-and-react-24d6dd3ca974
也许可以将样式作为字符串从文件中导入以使代码更有条理。
我遇到了同样的问题,找到了以下解决方法,您可以选择最适合您的方法
- 在你的 webpack 配置中定义两组规则来解析 css/less
文件。
- 第一条规则应该是包括所有全局样式,
假设它保存在 /styles/ 或类似目录中。
- 第二条规则是处理所有局部范围的 css 样式,理想情况下,这些样式应该靠近它们的组件。
- 您可以在定义规则时使用 include 和 exclude 选项来做到这一点
- 或者通过强制执行命名约定并相应地编写规则,例如所有 css 模块将是 [name].module.css 并且您的测试将检查 /.module.(less|css)$/ 并解析它。
示例如下:
// 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"
]
}
- 在写 css/less 时使用 :local 和 :global。如果启用 css 模块,它将默认为本地模式,您可以在选项中指定模式,如下所示:
{
loader: "css-loader",
options: {
modules: {
localIdentName: '[local]___[hash:base64:5]',
mode: 'global',
}
}
},
如果您将模式定义为全局模式,那么您包含的所有 css 类 都不会被哈希名称替换,而只有您指定为 :local 的那些才会被赋予唯一名称。例如:
/* this will remain as is */
.header {
color: blue;
}
:local {
/* this will become something like item_xSH2sa */
.item {
color: yellow;
}
}
- 定义一个函数来检查您的文件以确定它是 css 模块还是全局文件,使用 getLocalIdent 选项完成。这是我目前在我的设置中使用的方法。这也要求您的文件有一些命名约定,[name].module.less 用于 css 模块,[name].less 用于常规文件。
请参见下面的示例:
// 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:
在 reactapp
的起点导入全局样式。
整个 React 应用程序在 root 组件中 wrapped
。
它可以是 index.js
或 app.js
或 index.html
解决方案 2:
使用 scss
并创建 main.scss
文件并 导入 所有其他特别需要的 custom scss
文件到 main.scss
如果您想使用 css 模块,另一种简单的方法是:
<style jsx global>{`
.slick-prev:before,
.slick-next:before {
color: somecolor;
}
`}</style>
我可以说的最佳实践应该有一个 CSS 文件夹,您可以在其中保存整个应用程序所需的所有 CSS 就像我需要的所有组件中的字体大小是 20 所以需要遵循以下步骤:
- 创建一个名为 css/scss 的单独文件夹(首选 scss)。
- 创建文件
name _font.scss
.
- 创建一个文件
name index.scss
.
import _font.scss
里面 index.scss
(@import './fonts';
).
- 将其导入您的
index.js
起始文件 (import "../scss/index.scss"
)。
- 现在您可以在整个应用程序中使用您的 css。
在这种情况下,您可能会发现重复。例如 - 您在全局范围内拥有容器 CSS,它创建了您的文件之一,但您希望为您的文件之一创建一个单独的容器
这种情况为这个应用程序名称创建一个单独的 css/scss 文件应该像 (cssname.module.scss
) 必须包含 .module
以便更好地处理。
有了这个 css 你可以导入你的 jsx 文件 (import Style from './cssname.module.scss'
)
你可以像这样使用className= {Style.container}
但是如果你想一起使用你的一些全局和本地 css
从 npm 安装类名 (npm install classNames
)
使用方法:
import cn from 'Classnames'
className = {cn(Style.container,"fs-20 text-center")}
这里的 fs-20 和 text-center 是全局 CSS 出现在你的一些文件中
我目前正在使用 CSS 模块和 React 来设计我的样式。所以我的每个组件都在其组件特定的 css 文件中导入,如下所示:
import React from 'react';
import styles from './App.css';
const example = () => (
<div className={styles.content}>
Hello World!
</div>
);
export default example;
这在为单个组件设置样式时效果很好,但我如何应用非组件的全局样式(html、body、header 标签、div 等)具体的?
这可以通过简单地添加来完成:
require('./App.css');
(感谢@elmeister 正确回答了这个问题。)
由于您使用的是 ES6 导入语法,因此您可以使用相同的语法导入样式表
import './App.css'
此外,你可以用 :global
包装你的 class 以切换到全局范围(这意味着 CSS 模块不会修改它,例如:接下来添加一个随机 ID到它)
:global(.myclass) {
background-color: red;
}
我找到的全局导入样式的唯一方法,但仅针对特定路径是添加:
<style dangerouslySetInnerHTML={{__html: `
body { max-width: 100% }
`}} />
在 render
方法的 return 中。
否则,style
标签将添加到 <head>
,并且样式将应用于所有后续路线。
来自https://medium.learnreact.com/the-style-tag-and-react-24d6dd3ca974
也许可以将样式作为字符串从文件中导入以使代码更有条理。
我遇到了同样的问题,找到了以下解决方法,您可以选择最适合您的方法
- 在你的 webpack 配置中定义两组规则来解析 css/less
文件。
- 第一条规则应该是包括所有全局样式, 假设它保存在 /styles/ 或类似目录中。
- 第二条规则是处理所有局部范围的 css 样式,理想情况下,这些样式应该靠近它们的组件。
- 您可以在定义规则时使用 include 和 exclude 选项来做到这一点
- 或者通过强制执行命名约定并相应地编写规则,例如所有 css 模块将是 [name].module.css 并且您的测试将检查 /.module.(less|css)$/ 并解析它。
示例如下:
// 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"
]
}
- 在写 css/less 时使用 :local 和 :global。如果启用 css 模块,它将默认为本地模式,您可以在选项中指定模式,如下所示:
{
loader: "css-loader",
options: {
modules: {
localIdentName: '[local]___[hash:base64:5]',
mode: 'global',
}
}
},
如果您将模式定义为全局模式,那么您包含的所有 css 类 都不会被哈希名称替换,而只有您指定为 :local 的那些才会被赋予唯一名称。例如:
/* this will remain as is */
.header {
color: blue;
}
:local {
/* this will become something like item_xSH2sa */
.item {
color: yellow;
}
}
- 定义一个函数来检查您的文件以确定它是 css 模块还是全局文件,使用 getLocalIdent 选项完成。这是我目前在我的设置中使用的方法。这也要求您的文件有一些命名约定,[name].module.less 用于 css 模块,[name].less 用于常规文件。 请参见下面的示例:
// 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:
在 reactapp
的起点导入全局样式。
整个 React 应用程序在 root 组件中 wrapped
。
它可以是 index.js
或 app.js
或 index.html
解决方案 2:
使用 scss
并创建 main.scss
文件并 导入 所有其他特别需要的 custom scss
文件到 main.scss
如果您想使用 css 模块,另一种简单的方法是:
<style jsx global>{`
.slick-prev:before,
.slick-next:before {
color: somecolor;
}
`}</style>
我可以说的最佳实践应该有一个 CSS 文件夹,您可以在其中保存整个应用程序所需的所有 CSS 就像我需要的所有组件中的字体大小是 20 所以需要遵循以下步骤:
- 创建一个名为 css/scss 的单独文件夹(首选 scss)。
- 创建文件
name _font.scss
. - 创建一个文件
name index.scss
. import _font.scss
里面index.scss
(@import './fonts';
).- 将其导入您的
index.js
起始文件 (import "../scss/index.scss"
)。 - 现在您可以在整个应用程序中使用您的 css。
在这种情况下,您可能会发现重复。例如 - 您在全局范围内拥有容器 CSS,它创建了您的文件之一,但您希望为您的文件之一创建一个单独的容器
这种情况为这个应用程序名称创建一个单独的 css/scss 文件应该像 (cssname.module.scss
) 必须包含 .module
以便更好地处理。
有了这个 css 你可以导入你的 jsx 文件 (import Style from './cssname.module.scss'
)
你可以像这样使用className= {Style.container}
但是如果你想一起使用你的一些全局和本地 css
从 npm 安装类名 (npm install classNames
)
使用方法:
import cn from 'Classnames'
className = {cn(Style.container,"fs-20 text-center")}
这里的 fs-20 和 text-center 是全局 CSS 出现在你的一些文件中