一, 什么是 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 http://postcss.org/ ,PostCSS 是一个平台, 其中最常用到的插件就是 https://github.com/postcss/autoprefixer .
来源: https://www.cnblogs.com/xjnotxj/p/11584027.html