相关文章推荐
闯红灯的勺子  ·  html checkbox onchange-掘金·  1 年前    · 
慷慨大方的柚子  ·  node.js - Issue ...·  1 年前    · 
正直的茶叶  ·  领先技术 - ASP.NET Core ...·  1 年前    · 
坏坏的麦片  ·  typescript - ...·  1 年前    · 

原文链接: react中css实现方式 - 愧怍的小站 (kuizuo.cn)

与传统 html 标签类属性不同,react 中 class 必须编写为 className,比如

全局 css

.box {
  background-color:red;
  width:300px;
  height:300px;
function Hello() {
  return <div className='box'>
    hello react
  </div>
ReactDOM.render(
  <Hello/>,
  document.getElementById('root')

与传统在 html 标签定义 css 样式不同,因为这不是传统的 html 代码,而是 JSX,由于 class 作为关键字,无法作为标识符出现,比方说下面的代码将会报错。

const { class } = { class: 'foo' } // Uncaught SyntaxError: Unexpected token }
const { className } = { className: 'foo' }
const { class: className } = { class: 'foo' }

关于官方也有对此问题回答

有趣的话题,为什么 jsx 用 className 而不是 class

所以把传统的 html 代码强行搬运到 react 中,如果带有 class 与 style 属性,那么将会报错。

内联样式也得写成对象 key-value 形式,遇到-连字符,则需要大写,如

function Hello() {
  return <div className="box" style={{ fontSize: "32px",textAlign: "center" }}>
    hello react
  </div>

CSS 的font-size属性要写成fontSize,这是 JavaScript 操作 CSS 属性的约定

其实{ } 可传入表达式,比方这里传入的就是{ fontSize: "32px",textAlign: "center" } 对象,也可以将其定义为一个变量传入。

但是写内联样式显得组丑陋影响阅读,并且样式不易于复用,同时伪元素与媒体查询无法实现,但是封装成类样式,又会影响到全局作用域,所以便有了局部样式styles.module.css

局部样式 CSS Modules

Css Modules 并不是 React 专用解决方法,适用于所有使用 webpack 等打包工具的开发环境。以 webpack 为例,在 css-loader 的 options 里打开modules:true 选项即可使用 Css Modules。一般配置如下

loader: "css-loader", options: { importLoaders: 1, modules: true, localIdentName: "[name]__[local]___[hash:base64:5]" // 为了生成类名不是纯随机

然后通过 import 引入

import styles from './styles.module.css';
function Hello() {
  return <div className={styles.box}>
    hello react
  </div>

但如果是有多个局部样式,直接拼接是无效的(毕竟是个无效的表达式)

// 错误
<div className={style.class1 style.class2}</div>
// 正确
<div className={`${style.class1} ${style.class2}`}</div>
<div className={style.class1+ " " +style.class2}</div>
<div className={[style.class1,style.class2].join(" ")}</div>

classnames

还可以通过 npm 包 classnames 来定义类名,如

import classnames from "classnames";
import styles from './styles.module.css';
<div className={classnames(styles.class1,styles.class2)}></div>

最终都将编译为

<div class="class1 class2"></div>

当然 classnames 还有多种方式添加,就不列举了,主要针对复杂样式,根据条件是否添加样式。

但是 在 Css Module 中,其实能发现挺多问题的

如果类名是带有-连字符.table-size那么就只能styles["table-size"] 来引用,并且都必须使用{style.className} 形式。

最主要的是,css 都写在 css 文件中,无法处理动态 css。

CSS in JS

由于 React 对 CSS 的封装非常弱,导致了一系列的第三方库,用来加强 CSS 操作,统称为 CSS in JS(),有一种在 js 文件中写 css 代码的感觉,根据不完全统计,各种 CSS in JS 的库至少有47 种,其中比较出名的 便是styled-components

import styled from 'styled-components';
// `` 和 () 一样可以作为js里作为函数接受参数的标志,这个做法类似于HOC,包裹一层css到h1上生成新组件Title
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
  span {
    font-size: 2em;
// 在充分使用css全部功能的同时,非常方便的实现动态css, 甚至可以直接调用props!
const Wrapper = styled.section`
  padding: 4em;
  background: ${props => props.bgColor};
const Button = styled.a`
  /* This renders the buttons above... Edit me! */
  display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: transparent;
  color: white;
  border: 2px solid white;
  /* The GitHub button is a primary button
   * edit this to target it specifically! */
  ${props => props.primary && css`
    background: white;
    color: palevioletred;
const App = () => (
    <Wrapper bgColor='papayawhi'>
      <Title><span>Hello World</span>, this is my first styled component!</Title>
      <Button
      href="https://github.com/styled-components/styled-components"
      target="_blank"
      rel="noopener"
      primary
      GitHub
    </Button>
    </Wrapper>

像上面的 Title,Wrapper,Button 都是组件,Title 本质就是一个 h1 标签,在通过模板字符串编写局部 css 样式。

能直接编写子元素的样式,以及& :hover等 Sass 语法。

根据传入属性,在 css 中使用,Wrapper 传入背景颜色属性,Button 判断是否为 primary。

并且能方便的给暴露className props 的三方 UI 库上样式:

const StyledButton = styled(Button)` ... `

styled-jsx

vercel/styled-jsx: Full CSS support for JSX without compromises (github.com)

styled-jsx 概括第一印象就是 React css 的 vue 解决。yarn add styled-jsx 安装后,不用import,而是一个 babel 插件,.babelrc配置:

"plugins": [ "styled-jsx/babel" render () { return <div className='table'> <div className='row'> <div className='cell'>A0</div> <div className='cell'>B0</div> </div> <style jsx>{` .table { margin: 10px; .row { border: 1px solid black; .cell { color: red; `}</style> </div>;

只会作用到同级标签作用域,可以说是一种另类的内联样式了,如果不喜欢将样式写在 render 里,styled-jsx 提供了一个 css 的工具函数:

import css from 'styled-jsx/css'
export default () => (
    <button>styled-jsx</button>
    <style jsx>{button}</style>
  </div>
const button = css`button { color: hotpink; }`

简单说,就是将常用的 css 样式都封装完,只需要在 class 中引入即可

这里选用当红框架 Tailwind CSS 作为演示。

比方说 flex 布局的话,就需要写 dispaly: flex; 但是封装成类,如

.flex {
  dispaly: flex;

引用的时候直接在 class 中添加 flex 即可

<h1 class="flex">tailwindcss</h1>

贴一张官方演示图,把大部分常用的样式都封装成 class

官方在线例子(下图) Tailwind Play (tailwindcss.com)

有以下几种优点:

  • 源代码无非就是 css 的基本样式,如 class w-auto 对应 css width: auto; 等等
  • 如果不是特别复杂的样式,甚至可以不用写一条 css 代码,开发效率杠杠的。
  • 体积很小,更好的样式复用,并且打包后会根据所用的 class 进行打包,而非全部无用样式打包。
  • 与 bootstrap 设计不同,完全可以定制化不同类型的组件,而不是像 class="btn btn-danger" 这样。
  • 体验下来基本上就是在写内联样式 inline css 但是同时又不显得杂乱。

    组件化中使用

    在组件化开发中,完全可以自己实现一个 Button 按钮(上间距 pt-4,底部间距 pb-10,文字为 text-sky-500 天蓝色),

    const Button = ({ children, color }) => (
        <a className=`pt-4 pb-10 text-sky-500 ${color}`>{children}</a>
    

    不过要说缺点的话:

  • 可能之前标题只需要定义.title 类来完成全部样式,而 tailwind 需要好几个 css 原子类来实现
  • 初学者可能不适应,需要反复的查阅文档。(不过用多了,自然就会习惯了)
  • 最佳实现?

    介绍完几种 React 中 Css 的实现(当然还有很多库没介绍,主要挑几种主流的),实际又要选择哪种呢?

    说说我目前 react 所选的操作,tailwind(原子类)+ CSS modules,写一些小项目或者 demo 甚至都没必要写 css 代码,毕竟 css 是大多数前端程序员都不是那么想写的(包括我)。而做一些自定义的小组件的话那肯定是 styled-components,而 styled-jsx,对组件代码牺牲挺大所以不怎么写。

    不过每个人使用风格不同,我一开始接触原子类是 windicss,用久了之后习惯了常用的 class,编写起来可以说是相当的快捷了。

    不过相比 Vue 而言,react 的 css 实现着实费劲。

    参考链接:

    CSS Modules 用法教程 - 阮一峰的网络日志 (ruanyifeng.com)

    CSS in JS 简介 - 阮一峰的网络日志 (ruanyifeng.com)