阅读 344

2020年的css周边之styled-components原理及使用指南

本文作为 2020年的css周边:preprocessor、css-in-js等解决方案与methodology 的一部分用来说明css-in-js的用法,欢迎阅读


什么是styled-components

styled-components是一个js库,以下简称SC,我们可以利用其提供的api编写css以增强react组件系统的样式功能,其他css-in-js解决方案的思路也类似。

基本用法如下

//创建一个组件
import styled from 'styled-components';
const Title = styled.h1`
  font-size: 1.5em;
`;
//将刚创建的组件像其他react组件一样正常使用
render(
    <Title>
      Hello World!
    </Title>
);
复制代码

SC处理过css以后为我们提供了以下

  • 追踪页面上渲染的组件自动注入样式,结合代码拆分可以加载尽量少的代码。
  • 会生成独一无二的class names,不用担心重复、覆盖,这也是css-modules要实现的功能
  • 可以很清晰的知道哪些代码用了指定样式,更改或删除等维护方便
  • 基于props或者全局变量动态设置样式
  • 自动添加浏览器特定的前缀

基本原理

如果要学习一个js库,比使用更重要的是明白其原理,而使用只是在调用原理基础上暴露出来的api,因此这里对基本实现做一下简要介绍。

首先styled.h1``语法被称为Tagged Template Literal,类似直接函数调用styled.h1()(在SC中的具体作用参考The magic behind 💅 styled-components),它本质上就是一个组件工厂,用来返回各种带有我们自定义样式的组件。

当react开始渲染组件,即调用styled.h1 ,这相当于执行styled('h1')([样式])(因为在styled初始化时中将对应方法挂载到了上面),然后通过调用createStyledComponent方法经过一系列步骤生成组件提供给react。

在组件创建过程中会

  • 计算tagged template,获取componentStyle
  • 根据componentIdcomponentStyle等计算className
  • 使用STYLIS对样式添加浏览器对应前缀等预处理
  • 将生成的样式添加到style标签
  • 创建一个对应className的元素

通过对SC较为简单的分析,我们已经对其执行过程有了初步认识,现在我们看一下具体用法

指南

基本使用

除了上面介绍的用法还有

使用props

可以添加一个函数插值,其中参数就是props,比如

const Button = styled.button`
  /* Adapt the colors based on primary prop */
  background: ${props => props.primary ? "palevioletred" : "white"};
  color: ${props => props.primary ? "white" : "palevioletred"};
`;
render(
  <div>
    <Button>Normal</Button>
    <Button primary>Primary</Button>
  </div>
);
复制代码

扩展样式

以一个组件为基础生成另一个组件,基础组件可以是任意组件

//Button是一个组件
const TomatoButton = styled(Button)`
  color: tomato;
  border-color: tomato;
`;
复制代码

来自css的样式

可以将css文件中的样式导入使用,就像在使用cssModule一样

import styles from './styles.css'

<h1 className="title">
      Hello World
    </h1>
复制代码
//styles.css
.title {
  color: red;
}
复制代码

伪类、伪元素和嵌套

SC依赖的stylis可以提供类sass的语法来提供以上功能(想回顾sass的语法,请参考2020年的css周边之sass用法指南)

添加另外的或者重写props

使用.attrs方法添加另外的props

const Input = styled.input.attrs(props => ({
  // we can define static props
  type: "text",

  // or we can define dynamic ones
  size: props.size || "1em",
}))`
  padding: ${props => props.size};
`;
render(
  <div>
    <Input placeholder="A small text input" />
    <br />
    <Input placeholder="A bigger text input" size="2em" />
  </div>
);
复制代码

一些技巧

  • 用高优先级覆盖样式
const MyStyledComponent = styled(AlreadyStyledComponent)`
  &&& {
    color: palevioletred;
    font-weight: bold;
  }
`
复制代码

每个&都会生成一个类,比如

.MyStyledComponent-asdf123.MyStyledComponent-asdf123.MyStyledComponent-asdf123 {
  color: palevioletred;
  font-weight: bold;
}
复制代码
  • 覆盖行内样式
const MyStyledComponent = styled(InlineStyledComponent)`
  &[style] {
    font-size: 12px !important;
    color: blue !important;
  }
`
复制代码

结语

SC作为一个js库,相对于sass这种语言级别的工具,内容很少,更多用法请参考SC官方文档,现在可以继续去阅读2020年的css周边:preprocessor、css-in-js等解决方案与methodology其他部分啦🎨!

文章分类
前端
文章标签