一、什么是 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. static用法总结:

    这是我的第一篇随笔! 1.当1.cpp和2.cpp都定义了同一个全局时链接会报错,变量名冲突.需要将其中一个设置为static控制其作用域为只在一个源文件内部. 2.函数名也是全局的,故static的 ...

  2. JS基础-该如何理解原型、原型链?

    JS的原型.原型链一直是比较难理解的内容,不少初学者甚至有一定经验的老鸟都不一定能完全说清楚,更多的"很可能"是一知半解,而这部分内容又是JS的核心内容,想要技术进阶的话肯定不能对 ...

  3. C++中轻量级多线程openmp

    关于其概念及使用方法: https://baike.baidu.com/item/openmp/3735430?fr=aladdin

  4. pyinstaller打包出错numpy.core.multiarray failed to import

    py原文件运行时正常,但用pyinstaller打包为exe后,在运行则报错: 这是因为cv2要求的numpy版本与你装的numpy版本不一样,导致冲突:网上很多说升级numpy,但你把numpy升的 ...

  5. 感受一下.net中用 lambda与 linq 做数据集过滤的不同

    lambda: ids.Add( _hahahacontext .hahahamodel .FirstOrDefault( a => //lambda做过滤 a.name == "张宏 ...

  6. python暴力算法快乐数

    编写一个算法来判断一个数是不是"快乐数". 一个"快乐数"定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 ...

  7. 听说你不会调参?TextCNN的优化经验Tricks汇总

    前言:本篇是TextCNN系列的第三篇,分享TextCNN的优化经验 前两篇可见: 文本分类算法TextCNN原理详解(一) TextCNN代码详解(附测试数据集以及GitHub 地址)(二) 调优模 ...

  8. txt 文件的归并和分割

    1.归并 import os # 1.获取需要整合的文件目录下的 filepath = "G:\\我的python\\尹成\\python基础\\day13\\详细分类\\详细地区" ...

  9. [python] - 读取文件内容,并输出

    1.读取文件,并逐行输出内容,代码如下: # coding=gbk import os path = 'E:\python_practice' os.chdir(path) fname = raw_i ...

  10. SDU暑期集训排位(2)

    A. Art solved by sdcgvhgj 3min 签到 B. Biology solved by sdcgvhgj 85min 暴力 C - Computer Science solved ...