React中如何编写CSS

140 阅读5分钟

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;
}

image-20230118105147324.png

这样的编写方式和普通的网页开发中编写方式是一致的:

  • 如果我们按照普通的网页标准去编写,那么不会有太大的问题;
  • 但是组件化开发中我们希望组件是一个独立的模块,即使是样式也只是在自己内部生效,不会相互影响;
  • 但是普通的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;
}

image-20230118111153027.png

但是这种方案也有自己的缺陷:

  • 引用的类名,不能使用连接符(.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>
  )
}
​

image.png

另外,它支持类似于CSS预处理器一样的样式嵌套:
  • 支持直接子代选择器或后代选择器,并且直接编写样式;
  • 可以通过&符号获取当前元素;
  • 直接伪类选择器、伪元素等;

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的方式,大家请多多指正。