目录
用了 React 很久了,关于 react 中 css 作用域隔离一直不爽,这里总结一下在 React 中 优雅的写css。
- 方案一:namespaces
- 方案二:CSS in JS
- 方案三:CSS Modules
方案一: namespaces
利用约定好的命名来隔离 CSS 的作用域。这种方式不多加描述,大家都懂。
方案二:CSS in JS
目前的 CSS in JS 的第三方库有60余种,介绍两款我在使用的库
- styled-jsx
- styled-components
1. styled-jsx
我在之前的文章中有写过它,你可以参阅
import React from "react";
export default () => {
return (
<div className='container'>
<section className='main'>
<h1>111111</h1>
</section>
<style jsx>{`
.container {
height: 100vh;
background: royalblue;
}
.main {
height: 300px;
background: #61dafb;
}
`}</style>
</div>
);
}
缺点:但是 styled-jsx 的缺点在于,它无法修改第三方UI组件的样式,这让我很痛心。当我要修改第三方UI组件时只能用 css namespaces 使用
优点:但是优点也很明显,语法和 css 一致,没有学习成本
2. styled-components
安装
npm install --save styled-components
全局样式
// style.js
import { createGlobalStyle } from 'styled-components'
export const GlobalStyle = createGlobalStyle`
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
`;
项目入口文件index.js中加载全局样式 style.js
import React from 'react';
import ReactDOM from 'react-dom';
import { GlobalStyle} from './style.js';
import App from './App';
ReactDOM.render(
<>
<GlobalStyle/>
<App/>
</>,
document.getElementById('root')
);
局部(组件)样式
对于一个特定的组件,我们可以事先在render函数中,用组件的命名方式替换原本的div等标签
import React, {Component} from 'react'
import {
HeaderWrapper,
Nav,
NavItem
} from './style'
class Header extends Component {
render() {
return (
<HeaderWrapper>
<Nav>
<NavItem className='left active'>首页</NavItem>
<NavItem className='left'>下载App</NavItem>
<NavItem className='right'>登陆</NavItem>
<NavItem className='right'>
<span className='icon'>😄😄</span>
</NavItem>
</Nav>
</HeaderWrapper>
)
}
}
export default Header
然后在同目录下的style.js中编写具体的CSS样式,以组件名的形式导出
import styled from 'styled-components'
export const HeaderWrapper = styled.div`
position: relative;
margin: 0;
padding: 0;
height: 58px;
border-bottom: 1px solid #f0f0f0
`;
export const Nav = styled.div`
width: 945px;
height: 100%;
padding-right: 70px;
box-sizing: border-box;
margin: 0 auto;
display: flex;
justify-content: space-around;
`
export const NavItem = styled.div`
line-height: 56px;
padding: 0 15px;
font-size: 17px;
color: #333;
`
缺点:
1. jsx 中的原生标签不能一眼看出来,额外增加了标签变量
2. 使用不方便,与平时html + css 开发习惯相差较大
3. 也不能用来修改第三方组件样式
优点:
1. 样式写在 js 文件里,降低 js 对 css 文件的依赖。
2. 样式可以使用变量,更加灵活。
3. 使用方便,不需要配置 webpack、开箱即用。
4. SSR 类框架处理 CSS Modules 变量相当棘手,所以使用 styled-components 作方案
方案三:CSS Modules
利用 webpack 等构建工具使 class 作用域为局部。CSS 依然是还是 CSS
npm i -D style-loader css-loader
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
},
},
],
},
],
},
};
modules 更具体的配置项参考:css-loader | webpack 中文文档
loader 会用唯一的标识符 (identifier) 来替换局部选择器。所选择的唯一标识符以模块形式暴露出去。
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
mode: 'local',
// 样式名规则配置
localIdentName: '[name]__[local]--[hash:base64:5]',
},
},
},
],
},
],
},
};
App.js
...
import styles from "./App.css";
...
<div>
<header className={styles["header__wrapper"]}>
<h1 className={styles["title"]}>标题</h1>
<div className={styles["sub-title"]}>描述</div>
</header>
</div>
App.css
.header__wrapper {
text-align: center;
}
.title {
color: gray;
font-size: 34px;
font-weight: bold;
}
.sub-title {
color: green;
font-size: 16px;
}
编译后的 CSS,class 增加了 hash 值。
.App__header__wrapper--2_jgY {
text-align: center;
}
.App__title--GpMto {
color: gray;
font-size: 34px;
font-weight: bold;
}
.App__sub-title--1cIFi {
color: green;
font-size: 16px;
}
优点:解决了css局部作用域和模块依赖, 没有改造CSS,上手成本小,简单易用
缺点:对于不会webpack配置的同学有一定起步成本,但你可以参考我的webapck专栏教程https://blog.csdn.net/qq_41887214/category_10668880.html
参阅: