CSS 模块化

144 阅读1分钟

CSS

CSS 模块化的三种解决方案:

  1. CSS 命名约定 BEM规范(很早以前)

    BEM — Block Element Modifier

  2. 依旧使用 CSS,使用 JS 编译原生的 CSS 文件,使其具备模块化的能力 CSS-Modules

  3. 彻底抛弃 CSS,使用 JS 写 CSS 规则,并内联样式 CSS-IN-JS

1. CSS Modules 方案

CSS Modules 既不是官方标准,也不是浏览器的特性,而是在构建阶段对 CSS 类名选择器限定作用域的一种方式。

1.1 CSS Modules 如何使用

启用 CSS Modules

// webpack.config.js
 {
   test: /\.css$/i,
     use: [
       'style-loader',
       {
         loader: 'css-loader',
         options: {
           modules: true,
         },
       },
     ],
 },

css-loader 的配置

// webpack.config.js
 {
   test: /\.css$/i,
     use: [
       'style-loader',
       {
         loader: 'css-loader',
         options: {
           modules: {
             localIdentName: '[name]__[local]--[hash:base64:5]'
           },
         },
       },
     ],
 },

1.2 CSS Modules 的实践

结合 LESS 来使用

{
  test: /\.less$/i,
    use: [
      'style-loader',
      {
        loader: 'css-loader',
        options: {
          modules: {
            localIdentName: '[name]__[local]--[hash:base64:5]',
          },
          importLoaders: 1,
          sourceMap: true,
        },
      },
      {
        loader: 'less-loader',
        options: {
          sourceMap: true,
        },
      },
    ],
},

JS 和 CSS 之间共享变量

@bg-color: yellow;

:export {
  bgColor: @bg-color;
}

全局与局部的写法

.btn {
  color: green;
}

/* 与上面的写法等价 */
:local() {
  .btn {
    color: green;
  } 
}

/* 定义全局样式 */
:global() {
  .hr {
    color: red; 
  }
}

local 作用域会加 hash 字符串后缀

global 作用域不会加 hash 字符串

依赖关系管理

.btn {
    color: #fff;
    background-color: #1890ff;
    border-color: #1890ff;
}

.disabled {
  /* 1. 导入其他样式 */
  composes: btn
  /* 2. 动态导入样式文件 */
  composes: btn from './style/global.less';
  /* disabled 其它样式 */
  cursor: not-allowed;
  background-color: gray;
}

CSS Modules 是很好的 CSS 模块化解决方案,优势很明显,几乎没有学习成本,也不依赖任何的第三方库,并且对代码的侵入性也非常的小。

2. CSS-In-JS 方案

2.1 CSS-In-JS 不是一种库

第一阶段:原始的 HTML 页面

<div style="font-size:16px;color:red;" onclick="alert('Text')">
  My Text
</div>

第二阶段:关注点分离 – 不同的技术做不同的事情

3

第三阶段:Web Component 标准

2

function App() {
  const styles = {
    fontSize: 16,
    color: 'red',
  }
  return (
    <div style={styles} onClick="alert('Text')">
      My Text
    </div>
  )
}

原始的 HTML 写法是以 HTML 为载体,来写 JS 和 CSS

React 是以 JS 为载体,来写 HTML 和 CSS

CSS-In-JS 模式

CSS-In-JS 是一种把 CSS 直接写在 JS 里的一种模式,那么目前实现这种模式的第三方库有 63 种

2.2 Styled Component

Styled components – 以组件的形式写 CSS

普通写法

const Button = (props) => {
  const { children, ...otherProps } = props;
  return (
    <button
      style={{
        display: 'inline-block',
        border: '1px solid transparent',
        height: '32px',
        color: '#fff',
        backgroundColor: ' #1890ff',
        bordercolor: '#1890ff',
      }} 
      {...otherProps}
    >
      {children}
    </button>
  )
}

Styled components 写法 – 使用了 ES6 的标签模板方式来定义 CSS 样式,写法与原生 CSS 完全一致

const Button = styled.button`
  display: inline-block;
  border: 1px solid transparent;
  height: 32px;
  color: #fff;
  background-color: #1890ff;
  border-color: #1890ff;
`

// styled.button(`css`)

高级用法:

定义变量 & 逻辑推算

const color = '#1890ff';

export const Button = styled.button`
  display: inline-block;
  border: 1px solid transparent;
  height: 32px;
  color: #fff;
  background-color: ${props => props.red ? 'red' : color};
  border-color: ${color};
`;

继承

export const GreenButton = styled(Button)`
  background-color: green;
  border-color: green;
`;

背后的思想:分离逻辑组件和展示组件

使用 Styled components,可将组件分为逻辑组件和展示组件**,逻辑组件只关注逻辑相关的部分,展示组件只关注样式**。

Styled-components 最基本的理念就是通过移除样式与组件之间的对应关系来强制执行最佳实践。