Skip to content

一. React中CSS的概述


1.组件化天下的CSS

  • 前面说过,整个前端已经是组件化的天下:
    • CSS的设计就不是为组件化而生的,所以在目前组件化的框架中都在需要一种合适的CSS解决方案
  • 在组件化中选择合适的CSS解决方案应该符合以下条件:
    • 可以编写局部csscss具备自己的局部作用域,不会随意污染其他组件内的元素
    • 可以编写动态的css:可以获取当前组件的一些状态,根据状态的变化生成不同的css样式
    • 支持所有的css特性:伪类、动画、媒体查询等
    • 编写起来简洁方便、最好符合一贯的css风格特点

2.React中的CSS

  • 事实上,css一直是React的痛点,也是被很多开发者吐槽、诟病的一个点
  • 在这一点上,Vue做的要好于React
    • Vue通过在.vue文件中编写<style></style>标签来编写自己的样式
    • 通过是否添加scoped属性来决定编写的样式是全局有效还是局部有效
    • 通过lang属性来设置你喜欢的 less、sass等预处理器
    • 通过内联样式风格的方式来根据最新状态设置和改变css
  • VueCSS上虽然不能称之为完美,但是已经足够简洁、自然、方便了,至少统一的样式风格不会出现多个开发人员、多个项目采用不一样的样式风格
  • 相比而言,React官方并没有给出在React中统一的样式风格:
    • 由此,从普通的css,到css modules,再到css in js,有几十种不同的解决方案,上百个不同的库
    • 大家一致在寻找最好的或者说最适合自己的CSS方案,但是到目前为止也没有统一的方案

二. 内联样式CSS写法


  • 内联样式是官方推荐的一种css样式的写法:

    • style 接受一个采用小驼峰命名属性的js对象,,而不是CSS字符串
    • 并且可以引用state中的状态来设置相关的样式
  • 内联样式的优点:

    • 1.内联样式, 样式之间不会有冲突
    • 2.可以动态获取当前state中的状态
  • 内联样式的缺点:

    1. 写法上都需要使用驼峰标识
    2. 某些样式没有提示
    3. 大量的样式, 代码混乱
    4. 某些样式无法编写(比如伪类/伪元素)
  • 所以官方依然是希望内联适合和普通的css来结合编写

    image-20220912172952849

三. 普通CSS文件写法


  • 普通的css我们通常会编写到一个单独的文件,之后再进行引入
  • 这样的编写方式和普通的网页开发中编写方式是一致的:
    • 如果我们按照普通的网页标准去编写,那么也不会有太大的问题
    • 但是组件化开发中我们总是希望组件是一个独立的模块,即便是样式也只是在自己内部生效,不会相互影响
    • 但是普通的css都属于全局的css,样式之间会相互影响
  • 这种编写方式最大的问题是 样式之间会产生覆盖
image-20220912174112198

四. CSS Module写法


  • css modules并不是React特有的解决方案,而是所有使用了类似于webpack配置的环境下都可以使用css module
    • 如果在其他项目中使用它,那么我们需要自己来进行配置,比如配置webpack.config.js中的modules: true
  • React的脚手架create-react-app已经内置了css modules的配置
    • .css/.less/.scss 等样式文件都需要修改成.module.css/.module.less/.module.scss
    • 之后就可以引用并且进行使用了
  • css modules确实解决了局部作用域的问题,也是很多人喜欢在React中使用的一种方案
  • 最终生成的类名的格式是:文件名_类名_哈希值,如:Home_section_fxImn
  • 但是这种方案也有自己的缺陷:
    • 引用的类名,不能使用连接符(.xxx-xxx),在js中是不识别的
    • 所有的className都必须使用{module.className} 的形式来编写
    • 不方便动态来修改某些样式,依然需要使用内联样式的方式
  • 如果你觉得上面的缺陷还算OK,那么你在开发中完全可以选择使用css modules来编写,并且也是在React中很受欢迎的一种方式
image-20220912182528451

五. react脚手架中使用less的方案

  • 方案一:

    • 通过npm run eject命令暴露webpack文件,然后修改webpack配置,安装对应的loaderless-loader,css-loader,style-loader
  • 方案二:

    • cracocreate-react-app-config,一个对create-react-app进行自定义配置的社区解决方案)

    • ant design 本身是用less编写样式的,也是用react,其文档中有提到如何在react中使用less

    • ant design官网有对应的使用说明:https://ant.design/docs/react/use-with-create-react-app-cn#%E9%AB%98%E7%BA%A7%E9%85%8D%E7%BD%AE

    • 安装craco并修改 package.json 里的 scripts 属性

      shell
      npm i @craco/craco -D
    • 通过craco命令来运行,会合并根目录下的craco.config.js配置文件到webpack的配置里

      json
        // package.json
      
        "scripts": {
        -  "start": "react-scripts start"
        +  "start": "craco start"
        -  "build": "react-scripts build"
        +  "build": "craco build"
        -  "test": "react-scripts test"
        +  "test": "craco test"
        }
    • craco目前支持4.xcreate-react-app版本,如果我们脚手架create-react-app使用的5.x,可以安装aplha版本

      更新:

      • 2022-11-10

      • craco目前最新版本7.0.0开始支持5.x.x版本的react-scripts

        image-20221110220028773
    • craco作者对应的回答:https://github.com/dilanx/craco/issues/445

    • 加不加-D,都不影响项目开发,但是按照规范来,最好加上-D(即开发阶段依赖)

      shell
      npm i @craco/craco@alpha -D
    • 在项目根目录创建一个 craco.config.js 用于修改默认配置

      js
        // craco.config.js
      
        module.exports = {
          // ...
        };
    • 引入craco-less来帮助加载less样式和修改变量

    • 安装 craco-less

      • 如果有版本问题,导致安装失败,也可采取安装其对应的alpha版本
      • 按照规范来说,可以加-D,如果忘记加-D,不需要重新安装
      • 直接修改package.jsondependenciescraco-less对应的代码,移动到devDependencies中也是可以的
      • 这种东西对我们项目开发来说,不影响的,如果是用于第三方库开发,是需要注意的
      shell
      npm i craco-less -D
      npm i craco-less@alpha -D
    • 修改 craco.config.js 文件如下

      js
          const CracoLessPlugin = require('craco-less');
      
          module.exports = {
            plugins: [
              {
                plugin: CracoLessPlugin,
                // 下面这些是针对ant design增加的一些配置,如果没用到ant design,可以不配置下面的选项
                options: {
                  lessLoaderOptions: {
                    lessOptions: {
                      modifyVars: { '@primary-color': '#1DA57A' },
                      javascriptEnabled: true,
                    },
                  },
                },
              },
            ],
          };

六. CSS in JS解决方案


1.认识CSS in JS

  • 官方文档也有提到过CSS in JS这种方案:
    • CSS-in-JS” 是指一种模式,其中CSS js生成而不是在外部文件中定义
    • 注意此功能并不是React的一部分,而是由第三方库提供
    • React 对样式如何定义并没有明确态度
  • 在传统的前端开发中,我们通常会将结构(HTML)、样式(CSS)、逻辑(js)进行分离
    • 但是在前面的学习中,我们就提到过,React的思想中认为逻辑本身和UI是无法分离的,所以才会有了JSX的语法
    • 样式呢?样式也是属于UI的一部分
    • 事实上CSS-in-JS的模式就是一种将样式(CSS)也写入到js中的方式,并且可以方便的使用js的状态
    • 所以React又被人称之为 All in JS
    • 当然,这种开发的方式也受到了很多的批评:
    • Stop using CSS in JavaScript for web development
    • https://hackernoon.com/stop-using-css-in-javascript-for-web-development-fa32fb873dcc

2.认识styled-components

  • 批评声音虽然有,但是在我们看来很多优秀的CSS-in-JS的库依然非常强大、方便:

    • CSS-in-JS通过js来为CSS赋予一些能力,包括类似于CSS预处理器一样的样式嵌套、函数定义、逻辑复用、动态修改状态等等
    • 虽然CSS预处理器也具备某些能力,但是获取动态状态依然是一个不好处理的点
    • 所以,目前可以说CSS-in-JSReact编写CSS最为受欢迎的一种解决方案
  • 目前比较流行的**CSS-in-JS的库**有哪些呢?

    • styled-components
    • emotion
    • glamorous
  • 目前可以说styled-components依然是社区最流行的CSS-in-JS库,所以我们以styled-components的讲解为主

  • 安装styled-components

    shell
    npm i styled-components

3.ES6标签模板字符串

  • ES6中增加了模板字符串的语法,这个对于很多人来说都会使用

  • 但是模板字符串还有另外一种用法:标签模板字符串(Tagged TemplateLiterals

  • 我们一起来看一个普通的js的函数:

    • 正常情况下,我们都是通过函数名()方式来进行调用的,其实函数还有另外一种调用方式:

      image-20220912213950881
  • 如果我们在调用的时候插入其他的变量:

    • 模板字符串被拆分了
    • 第一个元素是数组,是被模块字符串拆分的字符串组合
    • 后面的元素是一个个模块字符串传入的内容
  • styled components中,就是通过这种方式来解析模块字符串,最终生成我们想要的样式的

4.styled的基本使用

  • styled-components的本质是通过styled函数的调用,最终创建出一个组件

    • 这个组件会被自动添加上一个唯一的class
    • styled-components会给该class添加相关的样式
  • 另外,它支持类似于CSS预处理器一样的样式嵌套:

    • 支持直接 子代选择器 或 后代选择器,并且直接编写样式

    • 可以通过&符号获取当前元素

    • 直接伪类选择器、伪元素等

      image-20220912214430980

5.props、attrs属性

  • props可以传递

    image-20220912215841932·

  • props可以被传递给styled组件

    • 获取props需要通过${}传入一个插值函数,该函数会被自动调用,props会作为该函数的参数
    • 这种方式可以有效的解决动态样式的问题
  • 添加attrs属性,该属性可以设置props中某些属性的默认值,attrs属性本身也是一个函数,其返回值也是函数,可以形成链式调用

  • attrs定义的属性,也会被合并到props中的

    image-20220912215900486
  • 也可以这样写

    image-20220913154627874`

6.styled高级特性

  • 支持样式的继承

    • 通过styled函数传入对应的样式组件,可以实现样式的继承

      image-20220913155432700
  • styled设置主题

image-20220913155844105

七. classnames库使用


1.vue中添加class

  • vue中添加class是一件非常简单的事情:

  • 传入一个对象:

    vue
    	<div class="static" v-bind:class="{ active: isActive, 'aaa': isAaa}"></div>
  • 传入一个数组:

    vue
    	<div :class="[active, aaa]"></div>
  • 对象和数组混合使用:

    vue
    	<div :class="[{ active: isActive }, aaa]"></div>

2.React中添加class

  • ReactJSX给了我们开发者足够多的灵活性,你可以像编写js代码一样,通过一些逻辑来决定是否添加某些class

    image-20220913162251085
  • 这个时候我们可以借助于一个第三方的库:classnames

    js
    	npm i classnames
    • 很明显,这是一个用于动态添加classnames的一个库

      image-20220913162334177

Released under the MIT License.