React 中的 CSS
- 事实上 CSS 一直是 React 的痛点,也是被很多开发者吐槽、诟病的一个点;
- 在组件化中选择合适的 CSS 解决方案应该符合以下条件:
- 可以编写局部 CSS,不会随意污染其他组件内的原生;
- 可以编写动态的 CSS;
- 支持所有的 伪类、动画、媒体查询等 CSS 特性;
- 编写起来简洁方便、最好符合一贯的 CSS 风格特点;
- …
- 在这一点上,Vue 做的要远远好于 React:
- Vue 通过在 .vue 文件中编写 <style><style> 标签来编写自己的样式;
- 通过是否添加 scoped 属性来决定编写的样式是全局有效还是局部有效;
- 通过 lang 属性来设置 less、sass 等预处理器;
- 通过内联样式风格的方式来根据最新状态设置和改变 css;
- …
- React 官方并没有给出在 React 中统一的样式风格,有几十种不同的解决方案,上百个不同的库;
- 在这篇文章中,会介绍挑选四种解决方案来介绍:
- 方案一:内联样式的写法;
- 方案二:普通的 CSS 写法;
- 方案三:css modules;
- 方案四:css in js (styled-components);
React 中的 CSS 方案
内联样式
-
内联样式是官方推荐的一种 CSS 样式的写法:
- style 接受一个采用小驼峰命名属性的 JavaScript 对象,而不是 CSS 字符串;
- 可以引用 state 中的状态来设置相关的样式;
export default class App extends PureComponent { constructor(props) { super(props); this.state = { titleColor: "red" } } render() { return ( <div> <h2 style={{color: this.state.titleColor, fontSize: "20px"}}>我是App标题</h2> <p style={{color: "green", textDecoration: "underline"}}>我是一段文字描述</p> </div> ) } }
-
优点:
- 内联样式,样式之间不会有冲突;
- 可以动态获取当前 state 中的状态;
-
缺点:
- 写法上都需要使用驼峰标识;
- 某些样式没有提示;
- 大量的样式,代码混乱;
- 某些样式无法编写 (比如伪类/伪元素);
引入 CSS 样式文件
-
普通的 CSS 通常会编写到一个单独的文件,通过 import 引入;
JSXCSSimport React, { PureComponent } from 'react'; import './App.css'; export default class App extends PureComponent { render() { return ( <div className="app"> <h2 className="title">我是App的标题</h2> <p className="desc">我是App中的一段文字描述</p> </div> ) } }
.title { color: red; font-size: 20px; } .desc { color: green; text-decoration: underline; }
-
这样的编写方式和普通的网页开发中编写方式是一致的:
- 如果按照普通的网页标准去编写,那么也不会有太大的问题;
- 但是普通的 CSS 都属于全局的 CSS,样式之间会相互影响;
CSS Modules
-
CSS Modules 并不是 React 特有的解决方案,而是所有使用了类似于 webpack 配置的环境下都可以使用的,React 的脚手架已经内置了 CSS Modules 的配置:
- .css/.less/.scss 等样式文件都修改成 .module.css/.module.less/.module.scss 等;
- 之后就可以引用并且进行使用了;
-
CSS Modules 确实解决了局部作用域的问题,但是这种方案也有自己的缺陷:
- 所有的 className 都必须使用 {style.className} 的形式来编写;
- 不方便动态来修改某些样式,依然需要使用内联样式的方式;
JSXCSSimport React, { PureComponent } from "react"; import style from "./1.module.css"; export default class App extends PureComponent { render() { return ( <div> <h2 className={style.title}>我是标题</h2> <h2 className={style['title-2']}>我是标题</h2> </div> ); } }
.title { font-size: 24px; color: blue; } .title-2 { font-size: 24px; color: blue; } /* 可以通过以下方式定义全局样式 */ :global { .global-style { color: red; } }
CSS in JS
-
CSS-in-JS 是指一种模式,其中 CSS 由 JavaScript 生成而不是在外部文件中定义;
-
目前比较流行的 CSS-in-JS 的库有哪些呢?
- styled-components
- emotion
- glamorous
-
下面开始介绍 styled-components
- 安装
npm install styled-components --save
- 引入库
import styled from "styled-components";
- 定义样式组件
import React from "react"; import styled from "styled-components"; // 创建一个 h1 标签组件(styled.标签名) const Title = styled.h1` font-size: 20px; text-align: center; color: red; `; export default function App() { return <Title>Hello World</Title>; }
- 样式嵌套,可以使用选择器、伪元素、媒体查询以及各类的声明样式
import React from "react"; import styled from "styled-components"; const Title = styled.div` text-align: center; p { font-size: 20px; color: red; } `; export default function App({imgUrl}) { return ( <Title> <p>Hello World</p> </Title> ); }
- 创建全局样式
import { createGlobalStyle } from "styled-components"; export const GlobalStyle = createGlobalStyle` * { margin: 0; padding: 0; box-sizing: border-box; // background: pink } `
- 组件传参
import React from "react"; import styled from "styled-components"; const Title = styled.div` text-align: center; p { font-size: 20px; color: ${props => props.color}; } `; export default function App({themeColor}) { return ( <Title> <p color={themeColor}>Hello World</p> </Title> ); }
- 样式组件的继承
const BoringButton = styled.button` color: blue; background-color: green; `; // 继承 BoringButton 的样式,覆盖自己的 color const CoolButton = styled(BoringButton)` color: pink; `;
- 使用 css 辅助函数(公共样式)
import React from "react"; import styled, {css} from "styled-components"; // 公共样式 const commonStyle = css` color: white; font-size: 20px; `; const Button = styled.button` ${commonStyle}; background-color: red; `; const AnotherButton = styled.button` ${commonStyle}; background-color: green; `;
- as 多态属性:可用于更改样式组件的标签类型 (如 div 转为 button,button 转为 a 标签等), 也可传递自定义组件;
import React, { PureComponent } from "react"; import styled from "styled-components"; export const Button = styled.button` // background-color: blue; `; export const NewButton = styled.button` background-color: yellow; `; export default class App extends PureComponent { render() { return ( <div> <Button>我是一个按钮</Button> <Button as="a" href="https://www.badiu.com" target="_blank"> 我是使用as修改后的按钮 </Button> <Button as={NewButton}>我是一个新按钮</Button> </div> ); } }
- attrs:一种添加属性的方式,只能添加原生标签默认属性,不可自定义属性;
import React, { PureComponent } from "react"; import styled from "styled-components"; export const Input = styled.input.attrs({ type: "text", length: (props) => props.length || 10 })` background: palevioletred; border-radius: 3px; border: none; color: white; padding: ${(props) => props.padding}; `; export const PasswordInput = styled(Input).attrs({ type: "password" })` background: #8a8a8a; length: 300px; `; export default class App extends PureComponent { render() { return ( <div> <Input length="20" padding="10px"></Input> <PasswordInput></PasswordInput> </div> ); } }
- 安装
React✍️ 受控、非受控组件
上一篇