作者:mobiledu2502917177 | 来源:互联网 | 2023-10-09 23:35
本文由编程笔记#小编为大家整理,主要介绍了React css-in-js相关的知识,希望对你有一定的参考价值。
随着React、Vue等支持组件化的MVVM前端框架越来越流行,在js中直接编写css的技术方案也越来越被大家所接受。
为什么前端开发者们更青睐于这些css-in-js的方案呢?我觉得关键原因有以下几点:
1.css在设计之初对“组件化”的考虑是不完全的,css直接作用于全局,无法直接作用于某个组件内部的样式。
2.在我们的前端组件中有很多“组件样式随着数据变化”的场景,但传统css应对这种场景很无力。
3.虽然我们可以通过一些规范来规避问题,但是真正用起来太繁琐了,也不利于跨团队的写作。
实在是太繁琐了!如果这是一段业务代码(注意,是业务代码),那团队中的其他人去读这段代码的时候内心一定是比较崩溃的。当然,如果是维护基础组件的话,遵守BEM规范「块(block)、元素(element)、修饰符(modifier)」还是非常重要的。
使用一些命名规范(比如BEM规范)来约束className,比如下面这种:
1 // style.css
2 .form {
3 background-color: white;
4 }
5 .form__input {
6 color: black;
7 }
8
9 import './stype.css'
10 const App = props => {
11 return (
12
13
14
15 )
16 }
1、使用class开发的组件库,业务方可以很方便地由组件样式的覆盖。
2、基础组件库一般由专门的团队开发,命名规范能统一。
3、使用最基础的class,能有效降低组件库的大小。
1 const App = props => {
2 return (
3
123
4 )
5 }
这种方式是JSX语法自带的设置style的方法,会渲染出来内联样式,它有一个好处是可以在style中使用一些全局变量(但实际上,less等css预处理语言也是支持的)。另外,如果你只是要调一下组件的margin,这种写法也是代码量最小的写法。
2-3、css-loader(CSS Module)
使用webpack的css-loader可以在打包项目的时候指定该样式的scope,比如我们可以这样打包:
1 // webpack config
2 module.exports = {
3 module: {
4 loaders: [
5 {
6 test: /\.css$/,
7 loader: 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
8 },
9 ]
10 },
11 ...
12 }
1 // App.css
2 .app {
3 background-color: red;
4 }
5 .form-item{
6 color: red;
7 }
1 import styles from './App.css';
2 const App = props => {
3 return (
4
123
5
456
6 )
7 }
这样.app就会被编译为.App__app___hash这样的格式了。这种方式是借助webpack实现将组件内的css只作用于组件内样式,相比于直接写inline styling也是一个不错的解决方案。
但使用style['form-item']这种形式去className的值(并且我们单独编写css文件时一般也都会使用“-”这个符号),我觉得不少开发者会觉得很尴尬……
另外虽然webpack支持“-”和驼峰互相转换,但是在实际开发中,如果面对一个样式比较多的组件,在css文件中使用“-”然后在js组件中使用驼峰也是有一定的理解成本的。
顾名思义,css-in-js是在js中直接编写css的技术,也是react官方推荐的编写css的方案,在github.com/MicheleBert… 这个代码仓库中我们可以看到css-in-js相关的package已经有60多个了。
下面以emotion为例,介绍一下css-in-js的方案:
1 import { css, jsx } from '@emotion/core'
2 const color = 'white'
3 // 下面这种写法是带标签的模板字符串
4 // 该表达式通常是一个函数,它会在模板字符串处理后被调用,在输出最终结果前
5 // 我们可以通过该函数来对模板字符串进行操作处理
6 // 详细链接 —— https://developer.mozilla.org/en-US/docs/Web/Javascript/Reference/Template_literals
7 const App = props => {
8 return (
9
10 className={css`
11 padding: 32px;
12 background-color: hotpink;
13 font-size: 24px;
14 border-radius: 4px;
15 `}
16 >
17 This is test.
18
19 )
20 }
在开发业务代码的时候,由于维护人员较多且不固定,且代码规模会逐渐增大,不能保证 css 不会交叉影响,所以我们不能只通过规范来约束,而是要通过 css-in-js 这样的方案来解决 css 交叉影响问题。
我们选取了 github.com/MicheleBert… 仓库中支持功能全面且月下载量较多的几个css-in-js方案进行一下比较(其实它们在使用的时候都差距不大,主要是实现原理以及支持的特性有一些不太一样)
|
|
|
|
|
|
|
Automatic Vendor Prefixing、Pseudo Classes、Media Queries |
|
|
|
Automatic Vendor Prefixing、Pseudo Classes、Media Queries、Styles As Object Literals、Extract CSS File |
|
|
|
Automatic Vendor Prefixing、Pseudo Classes、Media Queries、Styles As Object Literals |
|
|
|
Automatic Vendor Prefixing、Pseudo Classes、Media Queries、Styles As Object Literals、Extract CSS File |
|
|
|
Automatic Vendor Prefixing、Pseudo Classes、Media Queries、Styles As Object Literals、Extract CSS File |
从体积来看:emotion的体积是最小的。
从技术生态环境(以及流行程度):styled-components的star最多,文档相对来讲也是最完善的。
从支持的特性来看:emotion、aphrodite、jss支持的特性是最多的。
所以新人可以尝试接触styled-components,综合来看emotion是一个相当不错的选择。
我们团队其实很早就开始使用React + emotion进行前端开发了。当时选择emotion主要的考虑就是它拥有最全面的功能,以及在当时的css-in-js方案中相对最小的体积。
而且emotion是为数不多的支持source-map的css-in-js框架之一。
首先让我们来看一下emotion做了什么,这是一个使用了emotion的React组件:
1 import React from 'react';
2 import { css } from 'emotion'
3 const color = 'white'
4 function App() {
5 return (
6
7 padding: 32px;
8 background-color: hotpink;
9 font-size: 24px;
10 border-radius: 4px;
11 &:hover {
12 color: ${color};
13 }
14 `}>
15 This is emotion test
16
17 );
18 }
19 export default App;
1
2
3
4
12
17
18
19
20
This is React.js test
21
22
23
我们可以看到emotion实际上是做了以下三个事情:
1、将样式写入模板字符串,并将其作为参数传入css方法。
2、根据模板字符串生成class名,并填入组件的class="xxxx"中。
3、将生成的class名以及class内容放到
6
7
hi
8