React 之 CSS编写方式

文章探讨了在React组件化开发中遇到的CSS管理问题,从内联样式、普通CSS文件、CSSModule到Less和CSSinJS(如styled-components)的各种解决方案。每种方法都有其优缺点,例如内联样式避免了样式冲突,但可能造成代码混乱;CSSModule实现了局部作用域,但限制了类名的使用;CSSinJS提供了动态性和更强的JavaScript集成,但学习曲线较陡峭。文章旨在帮助开发者选择适合自己的CSS策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概述

整个前端已经是组件化的天下,而CSS的设计就不是为组件化而生的,所以在目前组件化的框架中都在需要一种合适的CSS解决方案

在组件化中选择合适的CSS解决方案应该符合以下条件:

  • 可以编写局部css:css具备自己的具备作用域,不会随意污染其他组件内的元素;

  • 可以编写动态的css:可以获取当前组件的一些状态,根据状态的变化生成不同的css样式;

  • 支持所有的css特性:伪类、动画、媒体查询等;

  • 编写起来简洁方便、最好符合一贯的css风格特点;

  • 等等...

React官方并没有给出在React中统一的样式风格:
  • 由此,从普通的css,到css modules,再到css in js,有几十种不同的解决方案,上百个不同的库

  • 大家一直在寻找最好的或者说最适合自己的CSS方案,但是到目前为止也没有统一的方案

二、写法 - 内联样式CSS

1. 概念

内联样式是官方推荐的一种css样式的写法:
  • style 接受一个采用小驼峰命名属性的 JavaScript 对象 ( { {} } ),而不是 CSS 字符串

  • 并且可以引用state中的状态来设置相关的样式

2. 优点

  • 内联样式, 样式之间不会有冲突

  • 可以动态获取当前state中的状态

3. 缺点

  • 写法上都需要使用驼峰标识

  • 某些样式没有提示

  • 大量的样式, 代码混乱

  • 某些样式无法编写(比如伪类/伪元素)

官方是希望内联合适和普通的css来结合编写

4. 代码

import React, { PureComponent } from 'react';

export class App extends PureComponent {
  getPColor() {
    return 'purple';
  }
  getStyle() {
    return {
      color: 'yellow',
      fontSize: '50px'
    };
  }
  render() {
    const hSize = 40;
    return (
      <div>
        {/* 1. 直接写入 */}
        <h1 style={{ color: 'red' }}>React App</h1>

        {/* 2. 变量控制 */}
        <h2 style={{ fontSize: `${hSize}px` }}>React App</h2>

        {/* 3. 三元表达式 */}
        <p style={{ color: 30 > 40 ? 'red' : 'blue' }}>React content</p>

        {/* 4. 单个样式函数 */}
        <p style={{ color: this.getPColor() }}>React content</p>

        {/* 5. 样式函数 */}
        <p style={this.getStyle()}>React content</p>
      </div>
    );
  }
}

export default App;

三、写法 - 普通CSS文件

普通的css通常会编写到一个单独的文件,之后再进行引入
这样定义的css文件,不管在哪里引入,都是全局的css
  • 这样的编写方式和普通的网页开发中编写方式是一致的

  • 如果按照普通的网页标准去编写,那么也不会有太大的问题

  • 但是组件化开发中希望组件是一个独立的模块,即便是样式也只是在自己内部生效,不会相互影响

  • 但是普通的css都属于全局的css,样式之间会相互影响

  • 这种编写方式最大的问题是样式之间会相互层叠掉

css代码

.notice{
  /* 使用传递过来的变量 */
  color: var(--color);
  font-size: var(--fontSize);
  background-color: black;
}

组件使用

import React, { PureComponent } from 'react';
// 导入样式
import './style.css';

export class index extends PureComponent {
  render() {
    const fontSize = '40';
    return (
      <div>
        {/* 传递变量到css文件 */}
        <h1 className='notice' style={{ '--fontSize': `${fontSize}px`, '--color': 'pink' }}>
          React title
        </h1>
      </div>
    );
  }
}

export default index;

四、写法 - CSS Module

css modules确实解决了局部作用域的问题,也是很多人喜欢在React中使用的一种方案。
  • css modules并不是React特有的解决方案

  • 而是所有使用了类似于webpack配置的环境下都可以使用的

  • 如果在其他项目中使用它,那么需要进行配置

  • 比如配置webpack.config.js中的modules: true

  • React的脚手架已经内置了css modules的配置:

  • .css/.less/.scss 等样式文件都需要修改成 .module.css/.module.less/.module.scss

  • 之后就可以引用并且进行使用了

css代码

文件名称得改 => 比如 App.module.css
.title{
  color: red;
  font-size: 32px;
}

.content{
  color: blue;
  font-size: 24px;
}

组件使用

import React, { PureComponent } from 'react';
// 1. 这样导入
import appStyle from './App.module.css';

export class App extends PureComponent {
  render() {
    return (
      <div>
        {/* 2. 这样使用,可使用多个 */}
        <h1 className={`${appStyle.title} ${appStyle.text}`}>React title</h1>
        <h2 className={appStyle.content}>React content</h2>
      </div>
    );
  }
}

export default App;

缺点

  • 引用的类名,不能使用连接符(.home-title),在JavaScript中是不识别的

  • 所有的className都必须使用{style.className} 的形式来编写

  • 不方便动态来修改某些样式,依然需要使用内联样式的方式

五、写法 - Less的编写方式

使用less需要进行配置
1. 配置webpack,可以通过npm run eject => 暴露出webpack的配置
2. 使用carco => create-react-app confg 工具,进行配置

使用工具 - craco

安装

npm install @craco/craco => 安装工具
npm install craco-less => 加载less样式和修改变量

配置

package.js启动命令修改,用craco启动
  "scripts": {
    "serve": "craco start",
    "build": "craco build",
    "test": "craco test",
    "eject": "react-scripts eject"
  },
新建 craco.config.js 文件
const CracoLessPlugin = require('craco-less');

module.exports = {
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          // 注入变量
          lessOptions: {
            modifyVars: { '@primary-color': '#1DA57A' },
            javascriptEnabled: true
          }
        }
      }
    }
  ]
};
重新启动项目 => npm run serve

less代码

创建App.less 文件,less中可以使用连接符(.home-title)
@redColor:red;
@purpleColor:purple;

.box{
  .title{
    font-size: 20px;
    color: @redColor;
    &-active{
      color: @purpleColor;
    }
  }
  .content{
    font-size: 16px;
    // 使用craco.config.js中配置的@primary-color
    color: @primary-color;
  }
}

组件使用

import React, { PureComponent } from 'react';
import styles from './App.module.less';

export class App extends PureComponent {
  render() {
    return (
      <div className={styles.box}>
        <h2 className={`${styles.title} ${styles['title-active']}`}>title</h2>
        <p className={`${styles.content}`}>content</p>
      </div>
    );
  }
}

export default App;

六、写法 - CSS in JS

1. 前言

概念

官方文档也有提到过CSS in JS这种方案:
  • “CSS-in-JS” 是指一种模式,其中 CSS 由 JavaScript 生成而不是在外部文件中定义

  • 注意此功能并不是 React 的一部分,而是由第三方库提供

  • CSS-in-JS的模式就是一种将样式(CSS)也写入到JavaScript中的方式

  • 并且可以方便的使用JavaScript的状态

  • CSS-in-JS通过JavaScript来为CSS赋予一些能力

  • 包括类似于CSS预处理器一样的样式嵌套、函数定义、逻辑复用、动态修改状态等等

  • React有被人称之为 All in JS

  • CSS-in-JS是React编写CSS最为受欢迎的一种解决方案

目前比较流行的CSS-in-JS的库 :
  • styled-components - 更流行

  • emotion

  • glamorous

安装styled-components => npm install styled-components

题外话 - 标签模版字符串

安装vscode插件

插件 : vscode-styled-components

2. 基本使用

创建style.js文件
import styled from 'styled-components';
// 这里可以单独创建一个文件,设置统一变量
const color = 'red'

/**
 * AppWrapper
 * 用标签模版字符串来调用该函数 => 类似styled.div()这样的调用
 * 该函数返回一个React组件
 */
export const AppWrapper = styled.div`
  .box {
    .title {
      color: ${color};
      cursor: pointer;
      &:hover {
        color: orange;
      }
    }
    .content {
      color: blue;
    }
  }
`;
组件使用
import React, { PureComponent } from 'react';
import { AppWrapper } from './style.js';

export class App extends PureComponent {
  render() {
    return (
      // <div className='app'> 变成了下面的写法,因为在style.js中已经写了
      <AppWrapper>
        <div className='box'>
          <h2 className='title'>title</h2>
          <p className='content'>content</p>
        </div>
      </AppWrapper>
      // </div>
    );
  }
}

export default App;
效果

3. 传递props

可以有效的解决动态样式的问题
组件传递,在样式中通过函数拿到传入的值,如果未传入,会使用默认的值
组件使用
import React, { PureComponent } from 'react';
import { AppWrapper } from './style.js';

export class App extends PureComponent {
  constructor() {
    super();

    this.state = {
      color: 'green',
      fontSize: '60'
    };
  }
  render() {
    const { color, fontSize } = this.state;
    return (
      // 这样写的话,AppWrapper组件就可以接收到color和fontSize这两个属性了
      <AppWrapper color={color} fontSize={fontSize}>
        <div className='box'>
          <h2 className='title'>title</h2>
          <p className='content'>content</p>
        </div>
      </AppWrapper>
    );
  }
}

export default App;
style.js文件
import styled from 'styled-components';

export const AppWrapper = styled.div`
  .box {
    .title {
      /* props会作为一个函数的参数,在这里拿到 */
      color: ${(props) => props.color};
      cursor: pointer;
      &:hover {
        color: orange;
      }
    }
    .content {
      font-size: ${({ fontSize }) => fontSize}px;
      color: blue;
    }
  }
`;

4. 设定attrs

可对传过来的值进行处理,attr( 这里是一个函数,后返回一个对象 )
import styled from 'styled-components';

export const AppWrapper = styled.div.attrs((props) => ({
  // 通过props拿到传入的值
  // 并且可以做一些处理,color,可以通过props.color,并且当color没有传入时,可以设置默认值
  color: props.color || 'red',
  // 还可以直接定义一些默认值
  border: '1px solid red'
}))`
  .box {
    .title {
      /* 使用的是上方attrs中处理过的值 */
      color: ${(props) => props.color};
      cursor: pointer;
      /* 使用attrs中定义的值 */
      border: ${(props) => props.border};
    }
    .content {
      font-size: ${({ fontSize }) => fontSize}px;
      color: blue;
    }
  }
`;

5. styled高级特性

七、添加class

1. vue中

2. react中

React在JSX给了开发者足够多的灵活性,但是一旦动态的类多了后,就不太友好了
render() {
  const index = 3;
  return (
    <div className={styles.box}>
      {/* 使用 && */}
      <h2 className={`${styles.title} ${index === 3 && styles['title-active']}`}>title</h2>
      {/* 使用 三元运算符 */}
      <p className={`${styles.content} ${index === 2 ? styles['title-active'] : ''}`}>content</p>
    </div>
  );
}
可使用一个第三方的库: classnames => npm i classnames
import React, { PureComponent } from 'react';
import styles from './App.module.less';

// 1. 使用classnames
import classnames from 'classnames';

export class App extends PureComponent {
  render() {
    const index = 3;
    return (
      <div className={styles.box}>
        {/* 使用 && */}
        <h2 className={`${styles.title} ${index === 3 && styles['title-active']}`}>title</h2>
        {/* 使用 三元运算符 */}
        <p className={`${styles.content} ${index === 2 ? styles['title-active'] : ''}`}>content</p>

        {/* 2. 使用classnames,调用classnames()函数即可 */}
        <p
          className={classnames('aaa', 'bbb', styles.title, {
            [styles['title-active']]: index === 3
          })}>
          content
        </p>
      </div>
    );
  }
}

export default App;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值