一、什么是 CSS in JS


上图来源:https://2019.stateofcss.com/technologies/

CSS in JS 是2014年推出的一种设计模式,它的核心思想是把 CSS 直接写到各自组件中,而不是单独的样式文件里。

CSS in js 的发展:

  • 最早就是内联样式

  • 依旧使用 CSS,但使用 JS 来管理样式依赖,代表是 CSS Modules。

    这种方式在React框架中引入的。

  • 使用 JavaScript 生成 CSS 然后插入到页面中的方式。例如 Styled Components。

    CSS Module 还是 JS 和 CSS 分离的写法,而 styled components 实际上是在 JS 上写 CSS了。

CSS in js 一次又一次的违背了 CSS 与 JS 分离的原则。

二、常见的 CSS in JS


1、CSS Modules

CSS Modules 能最大化地结合现有 CSS 生态和 JS 模块化能力,API 简洁到几乎零学习成本。

(1)安装

CSS Modules 提供各种插件,支持不同的构建工具。本文使用的是 Webpack 的css-loader插件。

CSS Modules不局限于你使用哪个前端库,无论是 React、Vue 还是 Angular,只要你能使用构建工具进行编译打包就可以使用。

本文以 react 为例。下同。

(2)全局/局部作用域

CSS 是全局的,没有局部作用域的功能。

但 CSS Modules 默认有局部作用域的概念,实现的方法为:使用独一无二的 class 名

这个独一无二的 class 名,是一个 hash 值,css-loader默认的生成算法是[hash:base64],但 webpack 配置里面可以自定义格式。

CSS Modules 只会对 className 以及 id 进行转换,其他的比如属性选择器,标签选择器都不进行处理,推荐尽量使用 className。

写法 - js:

import style from './App.css';

<h1 className={style.title_1}>
<h2 className={style.title_2}>

写法 - css

# 局部作用域的两种写法
.title_1 {} :local(.title_1) {} # 全局作用域的两种写法
:global(.title_2) {} :global {
.title_2 {}
  # 还能继续添加……
}

生成 - html:

<h1 class="_3zyde4l1yATCOkgn-DBWEL">

<h1 class="title_2">

生成 - css:

._3zyde4l1yATCOkgn-DBWEL {}

.title_2{}
(3)拓展 - 实现局部作用域的几种做法

1、嵌套(很深)选择器

.widget .table .row .cell .content .header .title {}

2、使用 BEM 的 class 命名规范

用很长的有规则的命名,来尽量实现唯一标识

className="widget__header--active"

参考我之前的文章《运用 CSS methodologies 去实现模块化》有介绍 BEM。

3、css modules 的做法

直接用 hash 生成 class 名。即没有方法1的嵌套,也绝对不会出现方法2中小概率的命名冲突问题。

(4)组合 composition

composes关键字可以让一个选择器可以继承另一个选择器的规则

很像 less 里的继承。

用处:

1、可以引入别的模块,是实现模块化的一个必要功能。

2、还能引入别的模块的部分样式。

写法 - css:

.title-base {
background-color: blue;
} # 1、来源于本文件
.title {
composes: title-base;
color: red;
} # 2、或 来源于别的文件
.title {
composes: title-base from './another.css';
color: green;
}

生成 - html:

<h1 class="_2DHwuiHWMnKTOYG45T0x34 _10B-buq6_BEOTOl9urIjf8">

生成 - css:

._10B-buq6_BEOTOl9urIjf8 {
background-color: blue;
} ._2DHwuiHWMnKTOYG45T0x34 {
color: red;
}

注意:这里是继承不是 mixin,所以这里没有混入所继承的选择器的属性,而是直接 addon 选择器名。减少了重复代码。

(5)使用变量

方法1:PostCSS 和 postcss-modules-values

方法2:搭配 less / sass

:export 关键字可以把 CSS 中的 变量输出到 JS 中。

/* config.scss */
$primary-color: #f40; :export {
primaryColor: $primary-color;
}
/* app.js */

import style from 'config.scss';
// 会输出 #F40
console.log(style.primaryColor);
(6)结合

1、跟 CSS 预处理器结合

2、跟 BEM 等 CSS methodologies 结合

可参考我之前的一篇文章:CSS methodologies 去实现模块化

(7)实例

react - jsx :

import classNames from 'classnames';

…………

      <div className={styles.header}>
<ul className={styles.menu}>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<div className={styles.account}>
<button
type="button"
className={classNames(styles.btnLogin, {
[styles.active]: !!this.state.active,
})}
>
login
</button>
<button type="button" className={styles.btnRegister}>
register
</button>
</div>
</div>

react - less :

.header {
color: blue;
.menu {
color: red;
li {
color: green;
}
}
.account {
color: orange;
.btnLogin {
font-size: 15px;
}
.btnRegister {
font-size: 20px;
}
.btnLogin.active,
.btnRegister.active {
font-weight: bold;
}
}
}

注意点:

1、因为使用了 css module 所以不用担心类名重复。可以舍弃掉 BEM 那种很长的类名,在保证基本语意化的前提下采取尽量简单的类名

2、建议类名为驼峰,因为 js 里的 dot 取值形式对驼峰友好,而对styles.btn-login 会报错。

3、可在 less 中采取 Combined Class Names (如 .btnRegister.active)或 Nested Class Names

4、可以在 react 中用 classname 库提高书写效率(很适合搭配 state / props )。

# classname 用法
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'

5、写好多的styles.xxx很烦怎么办?可以用 babel-plugin-react-css-modules 自动加 styles 前缀。例子:

import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './table.css'; class Table extends React.Component {
render () {
return <div styleName='table'>
<div styleName='row'>
<div styleName='cell'>A0</div>
<div styleName='cell'>B0</div>
</div>
</div>;
}
} export default CSSModules(Table, styles);

另外,还可以方便的覆盖本地变量的样式:

import customStyles from './table-custom-styles.css';<Table styles={customStyles} />;

6、更多实践请参考 ant design pro (https://pro.ant.design/docs/style-cn),它们用的正是 css modules + less。

2、Styled Components

(1)安装

npm install styled-components

(2)使用

就拿一个 demo 举例:

import styled from 'styled-components';

const Wrapper = styled.section`
margin: 0 auto;
width: 300px;
text-align: center;
`;
const Button = styled.button`
width: 100px;
color: white;
background: skyblue;
`; render(
<Wrapper>
<Button>Hello World</Button>
</Wrapper>
);

注意:Styled Components 不支持 less 和 sass 语法。


由于 Styled Components 有些激进,本人目前不打算深入了解。

So,剩余部分待写。

拓展


1、CSS 预处理器 和 CSS 后处理器

共同点:CSS 预处理器 和 CSS 后处理器 都属于 CSS 处理器。

不同点:CSS 预处理器使用特殊的语法来标记需要转换的地方,而 CSS 后处理器可以解析转换标准的 CSS,并不需要任何特殊的语法。

CSS 后处理器的代表就是 PostCSS ,PostCSS 是一个平台,其中最常用到的插件就是 autoprefixer

运用 CSS in JS 实现模块化的更多相关文章

  1. CSS 和 JS 文件合并工具

    写 CSS 和 JavaScript 的时候, 我们会遇到一个两难的局面: 要么将代码写在一个大文件, 要么将代码分成多个文件. 前者导致文件难以管理, 代码复用性差, 后者则因为需要在载入多个文件令 ...

  2. 解决MVC中使用BundleConfig.RegisterBundles引用Css及js文件发布后丢失的问题

    ASP.NET MVC4,ASP.NET MVC5中对JS和CSS的引用又做了一次变化,在MVC3中我们这样引用资源文件: <link href="@Url.Content(" ...

  3. MVC 之 解决MVC中使用BundleConfig.RegisterBundles引用Css及js文件发布后的丢失

    在MVC3中我们这样引用资源文件: <link href="@Url.Content("~/Content/Site.css")" rel="s ...

  4. sea.js的模块化开发

    为什么使用sea.js? Sea.js 追求简单.自然的代码书写和组织方式,具有以下核心特性: 简单友好的模块定义规范:Sea.js 遵循 CMD 规范,可以像Node.js 一般书写模块代码. 自然 ...

  5. 前端性能优化 css和js的加载与执行

    一个网站在浏览器端是如何进行渲染的? html本身首先会被渲染成 DOM 树,实际上 html 是最先通过网址请求过来的,请求过来之后,html 本身会由一个字节流转化成一个字符流,浏览器端拿的就是字 ...

  6. 了解CSS in JS(JSS)以及在React项目中配置并使用JSS

    目录 认识JSS 什么是JSS JSS 的常见实现 JSS 的好处与坏处 好处 坏处 使用模块化CSS实现JSS 安装插件 在React项目中的tsconfig.json中添加配置 vscode项目中 ...

  7. 性能优化之html、css、js三者的加载顺序

    前言 我们知道一个页面通常由,html,css,js三部分组成,一般我们会把css文件放在head头部加载,而js文件则放在页面的最底部加载,想要知道为什么大家都会不约而同的按照这个标准进行构建页面, ...

  8. JQuery 加载 CSS、JS 文件

    JS 方式加载 CSS.JS 文件: //加载 css 文件 function includeCss(filename) { var head = document.getElementsByTagN ...

  9. grunt自定义任务——合并压缩css和js

    npm文档:www.npmjs.com grunt基础教程:http://www.gruntjs.net/docs/getting-started/ http://www.w3cplus.com/to ...

随机推荐

  1. .NET使用Bogus生成大量随机数据

    .NET如何生成大量随机数据 在演示Demo.数据库脱敏.性能测试中,有时需要生成大量随机数据.Bogus就是.NET中优秀的高性能.合理.支持多语言的随机数据生成库. Bogus的Github链接: ...

  2. html中video标签

    video标签: <video src="视频的后缀名是.webM/.ogg/.mp4 "></video>属性: src:用于告诉video标签需要播放的 ...

  3. 【Fishing Master HDU - 6709 】【贪心】

    题意分析 题意:题目给出n条鱼,以及捕一条鱼所用的时间k,并给出煮每一条鱼的时间,问抓完并煮完所有鱼的最短时间. 附题目链接 思路: 1.捕第一条鱼的时间是不可避免的,煮每条鱼的时间也是不可避免的,这 ...

  4. NDK Cmake

    CMake与NDK搭配使用时,可以配置的部分变量: 1. `ANDROID_PLATFORM`:指定Android的目标版本,对应`$NDK/platforms/`目录下的版本.通常情况下是`defa ...

  5. Java中synchronized关键字你知道多少

    1.什么是synchronized 我们将其理解为同步锁,可以实现共享资源的同步访问,解决线程并发的安全问题.synchronize翻译成中文:同步,使同步.synchronized:已同步. 1.1 ...

  6. python2和python3的解释器安装

    python环境及安装 主板:人的骨架 用于扩展设备 CPU:人的大脑 用于计算和逻辑处理 硬板:肚子 存储数据(永久存储) C盘···· 内存:存储数据(临时储存) 没有保存会消失 电源:人的心脏 ...

  7. MIT HAKMEM算法-BitCount算法

    MIT HAKMEM算法 1.问题来源 牛客刷题 问题描述: #include <iostream> using namespace std; unsigned int fib(int n ...

  8. codeforce#483div2D-XOR-pyramid+DP

    题意:求给定区间中最大的连续异或和: 思路:DP的思想,先dp求出每个区间的异或和,再dp更新成当前这个dp[i][j]和dp[i-1][j].dp[i-1][j+1]中的最大值: 这样可以保证是同一 ...

  9. 牛客暑假多校第二场 F trade

    题意: 白兔有n个仓库,每个仓库有啊ai个货物,在每个仓库白兔可以装上任意数量的货物,也可以卸下任意数量的货物,现在有k个圆形信号阻隔器,然后有m个顾客下个一个订单,每个顾客的收货量有一个上限, 在每 ...

  10. bzoj 4025 二分图 lct

    题目传送门 题解: 首先关于二分图的性质, 就是没有奇环边. 题目其实就是让你判断每个时段之内有没有奇环. 其次 lct 只能维护树,(反正对于我这种菜鸟选手只会维护树), 那么对于一棵树来说, 填上 ...