运用 CSS in JS 实现模块化
一、什么是 CSS in JS

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 实现模块化的更多相关文章
- CSS 和 JS 文件合并工具
写 CSS 和 JavaScript 的时候, 我们会遇到一个两难的局面: 要么将代码写在一个大文件, 要么将代码分成多个文件. 前者导致文件难以管理, 代码复用性差, 后者则因为需要在载入多个文件令 ...
- 解决MVC中使用BundleConfig.RegisterBundles引用Css及js文件发布后丢失的问题
ASP.NET MVC4,ASP.NET MVC5中对JS和CSS的引用又做了一次变化,在MVC3中我们这样引用资源文件: <link href="@Url.Content(" ...
- MVC 之 解决MVC中使用BundleConfig.RegisterBundles引用Css及js文件发布后的丢失
在MVC3中我们这样引用资源文件: <link href="@Url.Content("~/Content/Site.css")" rel="s ...
- sea.js的模块化开发
为什么使用sea.js? Sea.js 追求简单.自然的代码书写和组织方式,具有以下核心特性: 简单友好的模块定义规范:Sea.js 遵循 CMD 规范,可以像Node.js 一般书写模块代码. 自然 ...
- 前端性能优化 css和js的加载与执行
一个网站在浏览器端是如何进行渲染的? html本身首先会被渲染成 DOM 树,实际上 html 是最先通过网址请求过来的,请求过来之后,html 本身会由一个字节流转化成一个字符流,浏览器端拿的就是字 ...
- 了解CSS in JS(JSS)以及在React项目中配置并使用JSS
目录 认识JSS 什么是JSS JSS 的常见实现 JSS 的好处与坏处 好处 坏处 使用模块化CSS实现JSS 安装插件 在React项目中的tsconfig.json中添加配置 vscode项目中 ...
- 性能优化之html、css、js三者的加载顺序
前言 我们知道一个页面通常由,html,css,js三部分组成,一般我们会把css文件放在head头部加载,而js文件则放在页面的最底部加载,想要知道为什么大家都会不约而同的按照这个标准进行构建页面, ...
- JQuery 加载 CSS、JS 文件
JS 方式加载 CSS.JS 文件: //加载 css 文件 function includeCss(filename) { var head = document.getElementsByTagN ...
- grunt自定义任务——合并压缩css和js
npm文档:www.npmjs.com grunt基础教程:http://www.gruntjs.net/docs/getting-started/ http://www.w3cplus.com/to ...
随机推荐
- Hive 系列(七)—— Hive 常用 DML 操作
一.加载文件数据到表 1.1 语法 LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (p ...
- 启xin宝app的token算法破解——token分析篇(三)
前两篇文章分析该APP的抓包.的逆向: 启xin宝app的token算法破解--抓包分析篇(一) 启xin宝app的token算法破解--逆向篇(二) 本篇就将对token静态分析,其实很简单就可以搞 ...
- 900E关于导航站
--------------------------以下更新于20190826------------------------- 作用: 导航站为方便网址收藏之用,收录一些常用的网站,目前主要以本科常 ...
- CSS 之Grid网格大致知识梳理1
CSS所提供的关于网格Grid属性让我们可以更方便编写页面以及布局,而它的一些主要应用属性如下: 1.将父容器的display属性值设置为grid 即可将其转换为网格容器: 2.在网格容器中添加列的属 ...
- 宝塔安装Lsky Pro图床教程
欢迎访问我的个人博客皮皮猪:http://www.zhsh666.xyz Lsky Pro图床是一个支持本地.阿里云 OSS.腾讯云 COS.七牛云.又拍云等储存方式的基于PHP的开源图床. 项目主页 ...
- Java基础之抽象类与接口
Java基础之抽象类与接口 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的时候 ...
- 《高效休息法》IT从业者如何高效休息
这本书主要讲什么? 大脑疲劳和身体疲劳不同,身体再怎么休息,大脑疲劳还是会在不知不觉中积累 大脑是一个重量仅仅占体重2%,却消耗着20%能量的大胃王,这些能量大部分都用在了预设模式网络(Default ...
- Setup Factory 9 简单打包
由于项目资源太大,使用VS自带打包工具无法实现需求,所以Setup Factory 9进行打包生成多个文件的方案,下面记录使用方法: 一:这里点击下载:下载,提取码:tt7a 二:下载完安装需要注册码 ...
- 007 Linux系统优化进阶
一.更改 ssh 服务远程登录的配置 windows:默认远程端口和管理员用户 管理员:administrator port :3389 Linux:远程连接默认端口和超级用户 管理员:root ...
- ccflow关于流程引擎的父子流程的基本概念
关键字:驰骋BPM jflow,ccflow, 驰骋工作流引擎 父子流程概念:在管理活动中,通用的部分,公用的部分,可以被重复执行的部分的流程管理活动我们把他独立出来,成为子流程,可以被其他流程的管理 ...