Styled Components常见样式使用技巧

6,115 阅读4分钟

前言

最近有个项目接触到了Styled-Components觉得这是一个不错的Css-In-Js的方案,当然也有很多人提到emotion这个方案,因为我没有深入的去接触过后者,这里就不说谁好谁坏的。

这篇文章简单记录一下以下问题:

  1. Styled Components覆盖修改Antd的样式的问题
  2. 和Css共存,如何让Css覆盖Styled Components的样式
  3. Styled Components使用Css Modules
  4. Styled Components使用Less
  5. Css Modules配置报错问题

环境准备

首先我们使用Create-React-App脚手架初始化一个项目,对于开发React的人来说这个脚手架那是相当的好用。

npx create-react-app styled-demo

初始化完成后执行安装以下依赖,这里主要是安装antd styled-components和定制化Create-React-App项目的两个包, 配置Antd方面的内容可以查看

yarn add styled-components babel-plugin-import react-app-rewired customize-cra antd

根目录创建config-overrides.js,用customized-cra来增加babel-plugin-import配置动态引入Antd组件

const { override, fixBabelImports } = require('customize-cra');

module.exports = override(fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: 'css',
  })
);

替换package.json中的npm scripts,这里原本的eject无需替换,react-app-rewired并不提供该功能

"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",

精简App.js

import React from 'react';
import { Button } from 'antd';
import './App.css';

function App() {
  return (
    <div className="App">
      <Button type="primary">Button 1</Button>
    </div>
  );
}

export default App;

之后yarn start运行就可以看到一个Antd的蓝色按钮了

Styled Components覆盖修改Antd的样式的问题

新建src/style.js来创建一个button

import styled from 'styled-components';
import { Button } from 'antd';

export const StyledButton = styled(Button)`
  &.ant-btn-primary {
    color: red;
  }
`;

App.js中增加,后再运行就可以看到两个按钮了

<StyledButton type="primary">Button2</StyledButton>

简单看一下这里的结构,head标签中所有的样式都会被style标签追加进去,而我们styled-components生成的会被加载到尾部,根据Css优先级那么就不难理解我们上述覆盖Antd样式的原理了。

那么有人问了既然styled-components被放在了最后,那如果和普通引入Css的方式一起使用怎么样才能让Css中的优先级最高呢?这就引出我们的下一部分

和Css共存,如何让Css覆盖Styled Components的样式

src/App.css中添加样式

.CssDiv {
  color: #ccc;
}

src/App.js添加div

<StyledDiv className="CssButton">Div</StyledDiv>

可以看到我们的按钮3是红色,并没有变为#ccc的颜色这是为什么呢?我们来看一下style标签的顺序,依旧是styled-components生成的排在了最后。

那我们应该如何做呢?要么调整引用顺序(用webpack不太好调整,而且我们webpack配置目前还是不可见的),要么调整Css权重的优先级;我们采取第二种方案这里有个小技巧,直接将src/App.js中的class选择器重复一遍,这里通过这种方式来提升Css优先级就让div的文字变为#ccc实现效果了

.CssDiv.CssDiv  {
  color: #ccc;
}

Styled Components使用Css Modules

新建demo.module.css,这里需要注意react-rewired给我们提供了一种快速开启css modules的方式,只需要命名为xxx.module.css/less 等都可以直接开启

.ModuleText {
  color: #000;
}

src/App.js中添加,既可以玉兰看到效果

<div className={style.ModuleText}>
    css modules
</div>

配置less

安装less相关依赖

yarn add less less-loader

修改上面的demo.module.css为demo.module.less;同时src/App.js中的引用也要修改哦 修改config-overriddes.js 保存之后重新运行yarn start即可

module.exports = override(fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: 'css',
  }),
  addLessLoader({
    localIdentName: "[local]--[hash:base64:5]" // if you use CSS Modules, and custom `localIdentName`, default is '[local]--[hash:base64:5]'.
  })
);

彩蛋

各位尝试less之后有些人是不是看到了下面的错误

这是因为新的Create-React-App中引入的Css-Loader^3.0.0有一些break Change; 类似于localIdentName这样的属性在css-loader中移动到了modules对象中了,custom-cra在调用addLessLoader方法的时候无法正确传递配置;那么怎么解决呢?

yarn add customize-cra@next //更新最新的customize-cra
// 更新配置
addLessLoader({
    cssModules: {
      localIdentName: "[local]--[hash:base64:5]" // if you use CSS Modules, and custom `localIdentName`, default is '[local]--[hash:base64:5]'.
    }
})

重新运行之后就ok了。 想知道更多具体的原因可以参见issue,这里大家有什么想法可以写上去目前该功能还没有正式完成修改。下图是我的修改想法如果赞同点个赞,后续我也会提出pr的说不定作者就采纳了哈哈

附上2020年01月17日customize-cra next分支源码截图,这就是我们为什么要添加cssModules属性的原因