Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSS Modules 使用心得 #10

Open
sweeetcc opened this issue Oct 9, 2016 · 1 comment
Open

CSS Modules 使用心得 #10

sweeetcc opened this issue Oct 9, 2016 · 1 comment
Assignees

Comments

@sweeetcc
Copy link
Owner

sweeetcc commented Oct 9, 2016

css modules

接触 CSS Modules 的概念也有一段时间了,公司里和个人的一些项目中进行了不少的应用。这里对 CSS Modules 做一个简单的总结,结合自己使用的经历和心得说一说遇到过的问题和目前的理解。

css-modules-online

## CSS 工程化难题: ### 一、 CSS 全局污染

CSS 选择器作用于全局,虽然我们尽可能使用更规范的选择器使用规范,使用更“特殊”的选择器,但是在后期维护的过程中,仍然不可避免地发生 CSS 选择器 “污染”。

二、命名和选择器:

命名一直是比较让人头疼的问题,即使有很多现成的解决方案,但是很明显遵循一个规范写超长的变量名真的很麻烦……

选择器的使用也是一门艺术,在结构和交互复杂的页面中规划选择器样式是一个需要工程化解决的问题。

三、重用和管理:

CSS 的重用和管理在传统 CSS 中比较困难,也是工程化至关重要的事情,尤其是进行组件化开发的时候,组件之间的 CSS 独立性难以管理。

CSS 模块化解决方案:

一、LESS、SCSS & PostCSS

CSS 作为前端编程中占据基础地位的一部分,在工程化方面需要借助一定的工具去组织。如果只是靠规范去指定作用域,组织嵌套,会变得难以维护,更谈不上代码结构的清晰。

有很多 CSS 工程化方面的强有力工具,比如: LESS / SCSS,它们不仅是 CSS 的语法糖,更是为 CSS 编程提供了很多编程语言的特性,类似于变量、嵌套、函数、循环和模块等。而 PostCSS 则是集成了一系列 CSS 工具链,让我们可以使用构建工具,例如常用的 autoprefixer 为我们添加支持多浏览器的前缀等。

这些工具的优点是:

  • 加速了我们编写 CSS 的速度
  • 让 CSS 的代码结构和组织更加清晰,嵌套层次更加清晰
  • 提供了函数、引用等特性,能够方便的重用代码

缺点是什么呢?

  • 首先,代码的编写者仍然要非常认真的组织代码,后续维护开发人员也需要遵循一定的规范,以避免全局污染
  • 另外,CSS 中的变量命名等仍然需要考虑,避免冲突而又必须突出语义
  • 还有就是 CSS 我们仍然面临使用传统 CSS 编写样式时需要面对的选择器权重、样式覆盖等等问题

这个优缺点总结并不充分,对 SCSS 和 LESS、autoprefixer 熟悉但是并没有用到全部特性,从一个使用者的角度来看,我非常喜欢 SCSS 和 LESS 等的方式。

二、CSS in JS / JSON

这种方案是直接在 JS 中编写样式,例如 material-ui 。可以使用 radium 这种类似的库。在 JS 中管理样式解决了模块化的问题,但是不能使用 LESS、SCSS、PostCSS预处理器,如 :focus、 :active、:hover 伪类处理起来比较麻烦。

三、CSS with JS

CSS Modules 把 CSS 生态 和 JS 的模块化能力结合起来,用简洁的 API 和 webpack 这样的工具做到了 CSS 的模块化。

CSS Modules 是什么

css-modules-logo

CSS Modules

A CSS Module is a CSS file in which all class names and animation names are scoped locally by default. All URLs (url(...)) and @imports are in module request format (./xxx and ../xxx means relative, xxx and xxx/yyy means in modules folder, i. e. in node_modules).

我的大概理解是:

一个 CSS Module (CSS 模块) 就是一个文件,这个文件中定义的所有 class 名和 animation 名都是默认只是针对局部作用域的。所有 URL 和 @import 形式的引入如果以 './' 或者 '../' 等开头都会从相对路径去找;而 'xxx/yyy' 形式的引用则意味着会从类似 'node_modules' 的外部包中去找。

CSS Modules 会被编译成一种叫做 ICSS 的格式,但是这个是针对 loader 的,而非前端用户。写法上,基本和正常的 CSS 语法一致:

/* style.css */
.className {
  color: green;
}

当在 JS 模块中引入 CSS 模块时,CSS 模块会 export 一个包含着所有 local name(局部变量) 到 global name(全局变量) 映射的对象,我们使用 local name(局部变量) 作为键值,可以从这个对象中取到相应的 global name(全局变量)。

import styles from "./style.css";

element.innerHTML = '<div class="' + styles.className + '">';

CSS Modules 使用

一、 在项目中引入 CSS Modules:

使用 webpack 项目中,引入 css-loader,css-loader 支持 CSS Modules,需要在 webpack.config.js 中加入配置:

 {
   test: /\.css$/,
   loader: 'style!css?modules&localIdentName=[name]__[local]-[hash:base64:8]!postcss'
 },

在 JS 模块中引入 CSS 文件:

import React, { Component } from 'react';
import styles from './App.css';

class App extends Component {
  render() {
    return (
      <div className={styles.app}>
          <h1>CSS Modules demo</h1>
      </div>
    );
  }
}

export default App;

相应的 CSS 为:

.app {
    margin-top: 400px;
  text-align: center;
  animation: rotate 10s linear;
}

@keyframes rotate {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

css-modules-demo

变量格式可以由类似: [name]__[local]-[hash:base64:8] 去指定,具体参见 css loader 文档。

二、 命名:

官方推荐的命名方式是使用驼峰法,大概是因为驼峰法可以直接用 . 操作符取到相应的键值;我习惯上用中划线连接,对我来说更清晰一些。

三、 例外:

因为默认 CSS Modules 会对样式表中的 class 名称做 :local() 处理。如果不想生成针对局部的 local name 怎么办? 想要使 class 名称不被 localIndentName 处理,可以使用 :global() 来指定 class 名称为全局的,在 :global 中的 class 在编译后不会改变。

例如:

:global(.not-local) {
    color: cyan;
}

not-local

四、 组合:

可以组合 class,需要使用 composes。

例如:

.app {
    margin-top: 400px;
  text-align: center;
}

.app-more {
    composes: app;

    font-size: 40px;
    font-weight: bold;
    text-decoration: underline;
}

css-modules-composes

可以有多个 composes 的规则,但是所有 composes 的规则必须在其他规则之前声明。composes 扩展只针对 local class,并且要求 local class 选择器只是一个单独的 class name。

如上图所示,当一个 local class A composes 了另外一个 local class B 的时候,会在标签上应用这两个 class name -> A & B。

五、 依赖:

可以再一个 CSS Modules 中引入其他 CSS Modules。

例如:

.app-more {
    composes: app from './another.css';

    font-size: 40px;
    font-weight: bold;
    text-decoration: underline;
}
// another.css
.app {
  margin-top: 400px;
  text-align: center;
}

六、 结合其他编译器来使用:

CSS Modules 可以结合 LESS/SCSS 来使用,具体使用基本就是引入相应的 loader 即可。但是结合其他编译器会有一些问题,比如嵌套 和 composes 的冲突等。

CSS Modules 的好处

  • 不再有冲突。
  • 明确的依赖关系:比如写组件的时候,CSS 和模板文件非常明确。
  • 没有全局的CSS作用域(除非特别声明)。

使用技巧

  • 只用 class(and 伪类 和 伪元素) 来规定样式,不使用 ID 标签等其他选择器
  • 只用一个 class 规定标签样式,不嵌套
  • 使用 compose 来进行复用。
@sweeetcc sweeetcc changed the title hello world 5 CSS Modules 使用心得 Oct 10, 2016
@sweeetcc sweeetcc added the css label Oct 10, 2016
@sweeetcc sweeetcc self-assigned this Oct 22, 2016
@sweeetcc
Copy link
Owner Author

CSS Modules 结合 LESS/SCSS 使用有必要吗?或者有什么好处呢?等使用一段时间后再做评价吧。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant