React中有很多方式书写CSS样式,内联样式,CSS模块,CSS-in-JS等。下面总结一下。
1. 内联样式
内联样式是最简单直观的方式,样式直接写到组件中。这种方式只适合比较简单的样式,如果样式比较复杂,建议采用CSS Module的方式,这样能够使组件文件更加清爽。
下面是一个内联样式的例子,div
和h1
的样式直接写在组件中。
1 2 3 4 5 6 7 8 9 10
| import React from 'react'; function App() { return ( <div style={{ backgroundColor: '#f0f0f0', padding: '20px' }}> <h1 style={{ color: '#333', fontSize: '24px' }}>Hello, World!</h1> </div> ); } export default App;
|
稍微好一点的,将样式提取到变量中,看着更清爽一些。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import React from 'react'; function App() { const divStyle = { backgroundColor: '#f0f0f0', padding: '20px', };
const h1Style = { color: '#333', fontSize: '24px', };
return ( <div style={divStyle}> <h1 style={h1Style}>Hello, World!</h1> </div> ); } export default App;
|
2. 外部样式(非CSS模块)
这种方式直接将样式定义到外部文件中,假设有组件App.tsx和样式文件App.css
1 2 3 4 5 6 7 8 9
| .app { background-color: #f0f0f0; padding: 20px; } .title { color: #333; font-size: 24px; }
|
组件中直接import
样式文件
1 2 3 4 5 6 7 8 9 10 11 12
| import React from 'react'; import './App.css';
function App() { return ( <div className="app"> <h1 className="title">Hello, World!</h1> </div> ); } export default App;
|
这种方式的有点和缺点都很突出:
- 优点:简单易用,样式和逻辑分离,样式可以被多个组件复用。
- 缺点:全局样式冲突;样式选择器不一致导致样式失效。
这种方式的好处是做到了样式和逻辑的分离,样式可以被多个组件复用。但是弊端也很明显,那就是要人为保证组件中的样式选择器和外部样式文件中的选择器保持一致,如果不一致就会导致样式失效。这种错误非常隐蔽,IDE并不会提示。 - 比如你在组件中写了className='app'
,这是一个类选择器,但是在样式文件中写的是#app
- 这是一个id选择器,这样就会导致样式失效。
另外这种方式会导致全局样式冲突,如果多个组件使用了相同的类名,可能会导致样式覆盖的问题。
以上面的代码为例,假设有一个组件Button.tsx
,它也使用了.title
类名
1 2 3 4 5 6 7 8 9
| import React from 'react'; import './Button.css'; function Button() { return ( <button className="title">Click Me</button> ); } export default Button;
|
这样就会导致Button
组件的title
样式覆盖了App组件的title
样式。具体的覆盖方式取决于样式的加载顺序,一般来说后加载的样式会覆盖前面的样式。
3. CSS模块
CSS Module既不是一个框架,也不是原生CSS中的特性,它是通过打包工具(比如Webpack)来处理CSS文件的。它的原理是将CSS文件中的类名转换为一个唯一的字符串(通常会加hash),这样就可以避免全局样式冲突的问题。
一般来说,如果组件名字是App
,那么它的样式文件名就是App.module.css
。
在React中使用CSS Module需要注意,如果你的项目使用了TypeScript,那么需要在src
目录下定义一个类型声明文件global.d.ts
,内容如下,否则会出现typescript找不到模块的错误。
1 2 3 4
| declare module "*.module.css" { const classes: { [key: string]: string }; export default classes; }
|
还是以上面的代码为例,假设有组件App.tsx
和样式文件App.module.css
1 2 3 4 5 6 7 8 9 10
| .app { background-color: #f0f0f0; padding: 20px; }
.title { color: #333; font-size: 24px; }
|
组件中直接import
样式文件, 这种方式下编译工具会将样式文件返回为一个JS对象,我们可以直接使用这个对象来访问样式类名。通常使用styles
作为对象的名称。当然你也可以使用其他名称。
1 2 3 4 5 6 7 8 9 10 11
| import React from 'react'; import styles from './App.module.css'; function App() { return ( <div className={styles.app}> <h1 className={styles.title}>Hello, World!</h1> </div> ); } export default App;
|
这种方式的优点是:
- 避免了全局样式冲突的问题
- IED会自动提示选择器名称
CSS Module推荐使用驼峰命名法,比如myClass
这种,如果你想使用kebab-case
命名法(选择器中包含-
),那么不能使用styles.xxx
的方式来访问,要是用styles['xxx']
的方式来访问。比如下面例子中的title-text
类名。
1 2 3 4 5 6 7 8
| .app { background-color: #f0f0f0; padding: 20px; } .title-text { font-size: 20px; }
|
1 2 3 4 5 6 7 8 9 10 11 12
| import React from 'react'; import styles from './App.module.css';
function App() { return ( <div className={styles.app}> <h2 className={styles['title-text']}>Hello, World!</h2> </div> ); } export default App;
|
4. CSS-in-JS
CSS-in-JS是一种将CSS样式写在JavaScript中的方式,它的优点是可以使用JavaScript的变量和函数来动态生成样式。常用的库有styled-components
和emotion
。
下面以styled-components
为例,介绍一下CSS-in-JS的用法。
1
| npm install styled-components
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import React from 'react'; import styled from 'styled-components'; const AppContainer = styled.div` background-color: #f0f0f0; padding: 20px; `;
const Title = styled.h1` color: #333; font-size: 24px; `;
function App() { return ( <AppContainer> <Title>Hello, World!</Title> </AppContainer> ); } export default App;
|
CSS-in-JS最近几年使用的人不是很多,连他的维护者也要放弃他了,所以我们不推荐使用这种方式。