一、什么是 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. Hive 系列(七)—— Hive 常用 DML 操作

    一.加载文件数据到表 1.1 语法 LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (p ...

  2. 启xin宝app的token算法破解——token分析篇(三)

    前两篇文章分析该APP的抓包.的逆向: 启xin宝app的token算法破解--抓包分析篇(一) 启xin宝app的token算法破解--逆向篇(二) 本篇就将对token静态分析,其实很简单就可以搞 ...

  3. 900E关于导航站

    --------------------------以下更新于20190826------------------------- 作用: 导航站为方便网址收藏之用,收录一些常用的网站,目前主要以本科常 ...

  4. CSS 之Grid网格大致知识梳理1

    CSS所提供的关于网格Grid属性让我们可以更方便编写页面以及布局,而它的一些主要应用属性如下: 1.将父容器的display属性值设置为grid 即可将其转换为网格容器: 2.在网格容器中添加列的属 ...

  5. 宝塔安装Lsky Pro图床教程

    欢迎访问我的个人博客皮皮猪:http://www.zhsh666.xyz Lsky Pro图床是一个支持本地.阿里云 OSS.腾讯云 COS.七牛云.又拍云等储存方式的基于PHP的开源图床. 项目主页 ...

  6. Java基础之抽象类与接口

    Java基础之抽象类与接口 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的时候 ...

  7. 《高效休息法》IT从业者如何高效休息

    这本书主要讲什么? 大脑疲劳和身体疲劳不同,身体再怎么休息,大脑疲劳还是会在不知不觉中积累 大脑是一个重量仅仅占体重2%,却消耗着20%能量的大胃王,这些能量大部分都用在了预设模式网络(Default ...

  8. Setup Factory 9 简单打包

    由于项目资源太大,使用VS自带打包工具无法实现需求,所以Setup Factory 9进行打包生成多个文件的方案,下面记录使用方法: 一:这里点击下载:下载,提取码:tt7a 二:下载完安装需要注册码 ...

  9. 007 Linux系统优化进阶

    一.更改 ssh 服务远程登录的配置 windows:默认远程端口和管理员用户 管理员:administrator port :3389 Linux:远程连接默认端口和超级用户 管理员:root   ...

  10. ccflow关于流程引擎的父子流程的基本概念

    关键字:驰骋BPM jflow,ccflow, 驰骋工作流引擎 父子流程概念:在管理活动中,通用的部分,公用的部分,可以被重复执行的部分的流程管理活动我们把他独立出来,成为子流程,可以被其他流程的管理 ...