React中如何编写CSS
事实上,css一直是React的痛点,也是被很多开发者吐槽、诟病的一个点。
在这一点上,Vue做的要好于React:
- Vue通过在.vue文件中编写style标签来编写自己的样式;
- 通过是否添加scoped属性来决定编写的样式是全局有效还是局部有效;
- 通过lang属性来设置你喜欢的less、sass等预处理器;
- 通过内联样式风格的方式来根据最新状态设置和改变css;
- 等等...
Vue在CSS上虽然不能称之为完美,但是已经足够简洁、自然、方便了,至少统一的样式风格不会出现多个开发人员、多个项目采用不一样的样式风格。
相比而言,React官方并没有给出在React中统一的风格:
- 由此,从普通的css,到css modules,再到css in js,有几十种不同的解决方案,上百个不同的库;
- 大家一致在寻找最好或者说最合适自己的css方案,但是到目前为止也没有统一的方案;
下面我们来看看主流的几种方案:
内联样式
内联样式的特点:
- style接受一个采用小驼峰命名属性的javaScript对象,而不是css字符串
- 并且可以引用state中的状态来设置相关的样式;
例如:
<div style={{color: 'red',fontSize:30,fontWeight: '700'}}>hello React!</div>
注意:React 会自动添加 ”px” 后缀到内联样式为数字的属性后。如需使用 ”px” 以外的单位,请将此值设为数字与所需单位组成的字符串。
内联样式的优点:
- 样式之间不会冲突
- 可以动态获取当前state中的状态
内联样式的缺点:
- 写法上都需要使用驼峰命名
- 某些样式没有提示
- 大量的样式,易造成代码混乱
- 某些样式无法编写(比如伪类/伪元素)
但是官方表示,通常不推荐将style属性作为设置元素样式的主要方式。
普通的CSS
普通的css我们通常会编写到一个单独的文件,之后再进行引入。
例如:
// section-1
<div className='root'>CssSection1</div>
// section-1的css
.root {
color:red;
font-size: 14px;
font-weight: 600;
}
// section-2
<div className='root'>CssSection2</div>
// section-2的css
.root {
color:blue;
font-size: 24px;
}
这样的编写方式和普通的网页开发中编写方式是一致的:
- 如果我们按照普通的网页标准去编写,那么不会有太大的问题;
- 但是组件化开发中我们希望组件是一个独立的模块,即使是样式也只是在自己内部生效,不会相互影响;
- 但是普通的css都属于全局的css,样式之间会互相影响;
这种编写方式最大的问题是样式之间会互相层叠掉;
css modules
css modules并不是React特有的解决方案,而是所有使用了类似于webpack配置的环境下都可以使用的。
- 如果在其他项目中使用它,那么我们需要自己来配置,比如配置webpack.config.js中的modules: true等。
React的脚手架已经内置了css modules的配置:
- .css/ .less/ .scss 等样式文件都需要修改为 .module.css/ .module.less/ .module.scss等;
css modules确实解决了样式局部作用域的问题,也是很多人喜欢在React中使用的一种方案。
例如:
// jsx
import styles from './style.module.css';
<div>
<div className={styles.header}>我是头部</div>
<div className={styles.content}>我是内容</div>
<div className={styles.footer}>我是尾部</div>
</div>
// style.module.css
.header {
color: aqua;
font-size: 32px;
font-weight: 700;
}
.content {
color: red;
font-size: 24px;
font-weight: 500;
}
.footer {
color: green;
}
但是这种方案也有自己的缺陷:
-
引用的类名,不能使用连接符(.footer-title),在javaScript中是不识别的;需要使用[]语法
-
<div className={styles['footer-title']}>我是尾部</div>
-
-
所有的className都必须使用{style.className}的形式来编写
-
不方便动态来修改某些样式,依然需要使用内联样式的方式
CSS in JS
官方文档也有提到过CSS in JS这种方案:
- “CSS-in-JS” 是指一种模式,其中 CSS 由 JavaScript 生成而不是在外部文件中定义。
- 注意此功能并不是React的一部分,而是由第三方库提供;
- React对样式如何定义并没有明确态度;
在传统的前端开发中,我们通常会将结构(HTML)、样式(CSS)、逻辑(JavaScript)进行分离。
- 但是在React的思想中认为逻辑本身和UI是无法分离的,所以才会有了JSX的语法。
- 样式呢?样式也属于UI的一部分;
- 事实上CSS-in-JS的模式就是一种将样式(CSS)也写入到Javascript中的方式,并且可以方便的使用javaScript的状态;
- 所以React有被人称之为All in JS;
总的来说,CSS-in-JS是React中编写CSS最为受欢迎的一种解决方案;
css-in-js有很多第三方库,今天我们主要讨论的是社区中最流行的styled-components
安装styled-components:
// npm
npm install styled-components
// yarn
yarn add styled-components
styled-components的本质是通过函数的调用,最终创建出一个组件;这个组件会被自动添加上一个不重复的class,styled-components会给该class添加相关的样式。
import styled from "styled-components";
import React from 'react';
const StyledWrapper = styled.div`
margin: 0 auto;
color: #f00;
font-size: 32px;
font-weight: 700;
`;
const StyledComponents =(props) => {
return (
<StyledWrapper>StyledComponents</StyledWrapper>
)
}
- 支持直接子代选择器或后代选择器,并且直接编写样式;
- 可以通过&符号获取当前元素;
- 直接伪类选择器、伪元素等;
props、attrs属性
props可以传递
<InputWrapper type="password" left="20px"/>
props可以被传递给styled组件
- 获取props需要通过${}传入一个插值函数,props会作为该函数的参数;
- 这种方式可以有效的解决动态样式的问题;
添加attrs属性
const InputWrapper = styled.input.attrs({
placeholder: '请填写密码',
paddingLeft: props => props.left || '5px'
})`
border-color: red;
padding-left: ${props => props.paddingLeft};
`
styled-components高级特性
支持样式的继承
const HYButton = styled.button`
padding: 8px 30px;
border-radius: 5px;
`
const HYWarnButton = styled(HYButton)`
backgroud-color: red;
color: #fff;
`
设置主题
import { ThemeProvider } from 'styled-components';
<ThemeProvider theme={{color:'red',fontSize:'32px'}}>
<StyledWrapper>hello React!</StyledWrapper>
</ThemeProvider>
// styled
const StyledWrapper = styled.div`
color: ${props => props.theme.color};
font-size: ${props => props.theme.fontSize};
`;
React中动态添加class
这里介绍一个第三方的库:classnames
安装classnames:
npm install classnames
classNames('foo','bar'); // => 'foo bar'
classNames('foo',{ bar: true }); => 'foo bar'
classNames({'foo-bar': true}); => 'foo-bar'
classNames({'foo-bar': false}); => ''
classNames({foo: true},{bar: true}) => 'foo bar'
classNames({foo: true, bar: true}) => 'foo bar'
以上就是几种React中编写CSS的方式,大家请多多指正。