css-module

什么是CSS Modules

A CSS Module is a CSS file in which all class names and animation names are scoped locally by default. (CSS模块就是所有的类名都只有局部作用域的CSS文件)。

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的问题

  1. Global Namespace 全局命名空间

  2. Dependencies 依赖

  3. Dead Code Elimination 无用代码删除

  4. Minification 压缩

  5. Sharing Constants 共享常量

  6. Non-deteministic Resolution 不确定分辨率

  7. Isolation 作用域隔离

CSS Modules将作用域限制于组件中,从而避免了全局作用域的问题。可以使用简单的类命令而不必担心污染全局作用域。在支持样式复用的同时,避免命名冲突。

工作原理

CSS Modules need to be piped in a build step. 需要构建才能使用,可以看成webpack的一个组件。

基本工作方式是:当你在一个JavaScript模块中导入一个CSS文件时(例如,在一个 React 组件中),CSS模块将会定义一个对象,将文件中类的名字动态的映射为JavaScript作用域中可以使用的字符串。

  1. import styles from "./submit-button.css"
  2. styles: {
  3. common: "components_submit_button__common__abc5436",
  4. normal: "components_submit_button__common__abc5436 components_submit_button__normal__def6547",
  5. error: "components_submit_button__common__abc5436 components_submit_button__error__1638bcd"
  6. }

CSS Modules特性

Naming

button组件分别使用BEM Style和CSS Modules

BEM Style

  1. /* components/submit-button.css */
  2. .Button { /* all styles for Normal */ }
  3. .Button--disabled { /* overrides for Disabled */ }
  4. .Button--error { /* overrides for Error */ }
  5. .Button--in-progress { /* overrides for In Progress */
  1. <button class="Button Button--in-progress">Processing...</button>

With CSS Modules

  1. /* components/submit-button.css */
  2. .normal { /* all styles for Normal */ }
  3. .disabled { /* all styles for Disabled */ }
  4. .error { /* all styles for Error */ }
  5. .inProgress { /* all styles for In Progress */

类名在工程中不需要唯一,可以看成是在JavaScript模块中使用的类在样式表中的别名

使用require或者import引入css

  1. import styles from './submit-button.css';
  2. buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`

编译后最终生成

  1. import { Component } from 'react';
  2. import styles from './submit-button.css';
  3. export default class SubmitButton extends Component {
  4. render() {
  5. let className, text = "Submit"
  6. if (this.props.store.submissionInProgress) {
  7. className = styles.inProgress
  8. text = "Processing..."
  9. } else if (this.props.store.errorOccurred) {
  10. className = styles.error
  11. } else if (!this.props.form.valid) {
  12. className = styles.disabled
  13. } else {
  14. className = styles.normal
  15. }
  16. return <button className={className}>{text}</button>
  17. }
  18. }
  1. <button class="components_submit_button__normal__abc5436">
  2. Processing...
  3. </button>

Composition

  1. .className {
  2. color: green;
  3. background: red;
  4. }
  5. .otherClassName {
  6. composes: className;
  7. color: yellow;
  8. }
  1. .common { /* font-sizes, padding, border-radius */ }
  2. .normal { composes: common; /* blue color, light blue background */ }
  3. .error { composes: common; /* red color, light red background */ }
  4. .components_submit_button__common__abc5436 { /* font-sizes, padding, border-radius */ }
  5. .components_submit_button__normal__def6547 { /* blue color, light blue background */ }
  6. .components_submit_button__error__1638bcd { /* red color, light red background */ }
  7. import styles from "./submit-button.css"
  8. styles: {
  9. common: "components_submit_button__common__abc5436",
  10. normal: "components_submit_button__common__abc5436 components_submit_button__normal__def6547",
  11. error: "components_submit_button__common__abc5436 components_submit_button__error__1638bcd"
  12. }

Dependencies 继承样式

  1. .otherClassName {
  2. composes: className from "./style.css";
  3. }

global 定义全局样式

  1. :global(.clearfix::after) {
  2. content: '';
  3. clear: both;
  4. display: table;
  5. }

webpack和react中使用

webpack-demo

webpack将CSS文件作为CSS模块

  1. {
  2. test: /\.css$/,
  3. loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
  4. }

自定义hash类名

  1. [name]__[local]___[hash:base64:5]

react-css-modules

  1. import React from 'react';
  2. import CSSModules from 'react-css-modules';
  3. import styles from './table.css';
  4. class Table extends React.Component {
  5. render () {
  6. return <div styleName='table'>
  7. <div styleName='row'>
  8. <div styleName='cell'>A0</div>
  9. <div styleName='cell'>B0</div>
  10. </div>
  11. </div>;
  12. }
  13. }
  14. export default CSSModules(Table, styles);

使用styles可以重写组件的样式

  1. import customStyles from './table-custom-styles.css';
  2. <Table styles={customStyles} />;
  1. /* table-custom-styles.css */
  2. .table {
  3. composes: table from './table.css';
  4. }
  5. .row {
  6. composes: row from './table.css';
  7. }
  8. /* .cell {
  9. composes: cell from './table.css';
  10. } */
  11. .table {
  12. width: 400px;
  13. }
  14. .cell {
  15. float: left; width: 154px; background: #eee; padding: 10px; margin: 10px 0 10px 10px;
  16. }

参考

CSS Modules 详解及 React 中实践

understanding-the-css-modules-methodology

github-css-modules

css-modules

web64 css4