React CSS-In-JS 方案: Linaria Vs. Styled-Components

码林冰川
• 阅读 1526

在开发一个 React 应用时,其中一个比较大的挑战就是为应用选择一个合适的样式处理方案。因为我们需要考虑到样式的可维护性,开发体验,以及样式对应用性能的影响等。基于这些考虑,很多开发者会选择使用 CSS-in-JS 方案。CSS-in-JS 方案将 javascript 作用于编写应用样式上。这有利于提升样式的可维护性,在编写样式过程中使用更加模块化的方式,将「动态样式」引入 react 应用中。目前市面上有非常多的 CSS-in-JS 方案。本文选择了使用比较多的两个方案 LinariaStyled-components 进行比较

在本文中,我们将回顾这两个流行的 CSS-in-JS 方案: LinariaStyled-components 。我们将一起研究他们的功能,同时比较他们功能差异,性能以及生态。

CSS-in-JS 解决方案

CSS-in-JS 解决方案给我们提供了新的编写 CSS 的方式。这些方案使用以 javascript 为基础的 API 来创建和编写样式。主要的优点包括:

  • 动态样式:允许开发者编写动态 CSS
  • 元素作用域:可以把样式的范围固定在某些元素上
  • 消除无用代码:会自动除去应用中冗余的 CSS 代码
  • 支持自定义主题
  • 安装和设置简单
  • 支持 ES modules 和 作用域
  • 更加容易编写单元测试
  • 性能提升
  • 支持 SSR
  • 支持所有的 CSS 语法

Linaria

Linaria 是最流行的 CSS-in-JS 解决方案之一,GitHub 拥有 7.1k 个 star 和 260 个 fork。Linaria 是 「零运行时」方法,这意味着它将开发者写好的样式代码在构建时转换为一个单独的 .css 文件。这个行为跟很多的 CSS 预处理器相似,比如 SASS ,LESS

它提供了很多功能,包括:

  • 提供创建 CSS 类的 API 。”css” API 允许开发者创建所选择的样式,同时他也支持模版语法来满足当我们需要插入动态值。
import { css } from '@linaria/core';

const red = "red"
const header = css`
  text-transform: uppercase;
    color: ${red}
`;

<h1 className={header}>Hello world</h1>;

React CSS-In-JS 方案: Linaria Vs. Styled-Components

  • 它也提供可以创建元素的 API. “styled” API 允许开发者创建任何元素,比如: div,p,等等。当然,这个 API 也是支持模版语法来插入对应的变量值的
import { styled } from '@linaria/react'

const Container = styled.div`
  font-size: 35px;
  color: red;
  border: 1px solid red;

  &:hover {
    border-color: blue;
  }

  h1 {
    margin-bottom: 24px;
  }
`;

const App = () => {
    return <Container>
        <h1>Hello World</h1>
    </Container>
  }
export default App;

React CSS-In-JS 方案: Linaria Vs. Styled-Components

  • 它通过 React 的 Props 或者常规变量来管理动态样式。在下面的代码中,我们通过 React 组件传递 props 和一些常规变量到另一个元素上
import { styled } from '@linaria/react';

const Title = styled.h1`
  font-family: inherit;
`;
const medium = 30

const Navbar = styled.nav`
  font-size: ${medium}px;
  color: ${props => props.color};
  border: 1px solid red;

  &:hover {
    border-color: blue;
  }

  ${Title} {
    margin-bottom: 24px;
  }
`;

const App = () => {
    return <Navbar color="#999">
        <Title>Hello world</Title>
    </Navbar>
}

export default App;

React CSS-In-JS 方案: Linaria Vs. Styled-Components

其他的功能包括:

  • 通过 CSS source maps 可以很容易的找到样式变量是在哪里定义的
  • 可以在 JS 代码中开启 CSS Lint https://github.com/stylelint/...
  • 通过 @linaria/atomic 可以支持原子样式

Styled-Components

Styled-Components 也是流行的 CSS-in-JS 解决方案之一。在 GitHub 上拥有 37.2 k 的 star 和 2.3 k 的 forks。Styled-components 让开发者能够通过编写真实的 CSS 代码来修改组件的样式。它在组件和样式之间创建了一个抽象层,从而消除了直接的映射。

提供的能力,包括:

  • 自动提取关键 CSS 和 代码分割:Styled-Components 监控组件,并且在组件渲染到页面的时候插入组件必要的样式代码。同时支持代码分割来加快组件加载的速度
  • 为样式生成唯一的类名,以防止样式的覆盖,拼写错误以及冗余
  • Styled-component 也提供通过 props 或者常规变量为元素注入动态值。“styled” API 允许开发者创建选择的元素,跟 Linaria 一样,Styled-component 也支持大致相同的模版语法
import styled from 'styled-components';

const Button = styled.button`
  background: ${props => props.primary ? "palevioletred" : "white"};
  color: ${props => props.primary ? "white" : "palevioletred"};

  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
`;

const App = () => {
    return <div>
        <Button>Normal</Button>
        <Button primary>Primary</Button>
  </div>
}

export default App;

React CSS-In-JS 方案: Linaria Vs. Styled-Components

  • 样式扩展:Styled-Components 允许在已有的样式上通过 styled 进行扩展
import styled from 'styled-components';

const Button = styled.button`
  color: palevioletred;
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
`;

const TomatoButton = styled(Button)`
  color: tomato;
  border-color: tomato;
`;

const App = () => {
    return <div>
        <Button>Normal Button</Button>
        <TomatoButton>Tomato Button</TomatoButton>
    </div>
}

export default App;

React CSS-In-JS 方案: Linaria Vs. Styled-Components

React CSS-In-JS 方案: Linaria Vs. Styled-Components

其他的功能,包括:

  • 维护成本低
  • 更简便的删除不必要的 CSS
  • 支持 SSR
  • 支持主题定制

对比 Linaria 和 Styled-Components

开发者在很长一段时间都在选择最适合自己项目的样式解决方案,而 Linaria 和 Styled-Components 无疑是当中的佼佼者。接下来我们将从:「功能」,「性能」以及 「生态」来对这两个方案进行比较

功能

  • Linaria 是「零运行时」方案,这意味着样式文件会在构建时被单独抽取成 CSS 文件;Styled-Components 则是在构建时通过 javascript 将 CSS 注入,不会生成额外的 CSS 文件
  • 都拥有相似的 CSS 语法(类似 Sass 的风格)
  • 在 React 应用中都可以基于 Prop 实现变量注入(原理是使用 CSS 变量)
  • 都可以通过 CSS source maps 很快找到 CSS 变量定义的位置
  • 都可以通过 stylelint 的方案进行代码检查
  • 都使用 Javascript 来组织代码逻辑,无需使用 CSS 预处理器
  • 都可以平替 Sass 或者 PostCSS 方案

通过上述的的功能描述,我们发现 Linaria 和 Styled-Components 的 API 都比较相似,所以开发者很容易就可以从其中一个方案迁移到另一个方案

基于请求的性能对比

  • 在生产环境中, Linaria 会产生额外的 .css 文件,这将会引起 CSS 文件体积变大,文件数量变多,导致请求数量变多的问题
  • 对于 Styled-Components 来说,相同情况下,CSS 文件体积和数量无疑是更少的,但是会增加 JS bundle 的体积大小

许多争论在于认为 Linaria 产生的 css 文件对性能的影响是比较小的,相对于 Styled-Components ,Linaria 不会增加 JS bundle 体积是一种更好的取舍;而另一些则认为 Linaria 增加了 CSS 冗余代码的可能性。

我们可以在 这里 看到更多关于请求的性能对比

基于页面加载的性能对比

在加入多种页面加载标准之后发现,大部分的页面使用 Linaria 的加载性能要 好于 使用 Styled-Components。其中一个比较重要的原因就是,Linaria 导致的 CSS 资源体积与数量的增加对于页面加载的影响要小于 Styled-Components 导致的 JS bundle 体积的增加

我们可以从下面的资料中看到更多关于加载的对比

基于渲染和用户交互的性能对比

在这个方面的对比,主要是页面元素拖拽交互以及重新渲染;结果显示大部分的 Linaria 会有更少的脚本运行时间,更少的样式重绘重排

我们可以从下面的资料中看到更多关于渲染的对比

生态系统

Styled-components 目前拥有 37.2K GitHub stars, 2.3K GitHub forks,超过 4百万的 NPM 包周下载量,可以说是 CSS-in-JS 最大的生态系统方案;而 Linaria 只有 7.1K GitHub stars, 260 GitHub fork 和 16000 的 NPM 包周下载量。这意味着 Styled-components 会有更大的社区以及讨论热度,更多的课程(学习成本低)以及更多的问题解答等等

总结

本文我们先介绍了 Linaria 和 Styled-Component 的使用。然后又对比两者之间的功能,性能特点以及生态系统。

本文的代码地址:

参考资料

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Sass
嵌套规则(NestedRules)Sass允许将一套CSS样式嵌套进另一套样式中,内层的样式将它外层的选择器作为父选择器mainp{color:00ff00;width:97%;.redbox{
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
美凌格栋栋酱 美凌格栋栋酱
4个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(