CSS Modules

161 阅读1分钟

前言

作用域

CSS的规则都是全局的,任何一个组件的样式规则,都对整个页面有效。

产生局部作用域的唯一方法,就是使用一个独一无二的className的名字,不会与其他选择器重名。

编译过程

import React from 'react';
import style from './App.css';
export default () => {
  return (
    <h1 className={style.title}>
      Hello World
    </h1>
  );
};

构建工具会将类名style.title编译成一个哈希字符串。

<h1 class="_3zyde4l1yATCOkgn-DBWEL">
  Hello World
</h1>

这样一来,这个类名就变成独一无二了,只对App组件有效。这样也导致了一些问题比如css穿透,如果要改一些第三方的东西

样式穿透

vue怎么实现当前组件范围内有效的:在style上加一个scoped修饰符,这个样式就只在当前组件的范围内有效

在每个dom元素上,有一个data-v-xxxxxxxx的标识符,这个标识符就是保证scoped有效的根本!我们定位到button上,查看css样式:

image.png

解决方法: vue用sass语法/less语法 : 在要修改的样式前添加::v-deep ,/deep/也是可用的

.wrap /deep/ .el-card__header{
   border:none;
}

react如何解决:可以用global(.className)来做到样式穿透,就是让被global包裹住的class不被样式隔离化,维持原有的名称,写法的话类似这样就可以生效了

// Father的scss文件
.father {
  :global(.btnStyle){
    // 一些样式
  }
  // 或者
  :global(#btnStyle){
    // 一些样式
  }
}

// Father
<div className={styles.father}>
  <Son/>
</div>

// Son
<div className={styles.btnStyle} id='btnStyle'>
  这是一个按钮
</div>

使用方法

Webpack 的[css-loader]插件

module.exports = {
  entry: __dirname + '/index.js',
  output: {
    publicPath: '/',
    filename: './bundle.js'
  },
  module: {
    loaders: [
      {
        test: /.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: {
          presets: ['es2015', 'stage-0', 'react']
        }
      },
      {
        test: /.css$/,
        loader: "style-loader!css-loader?modules"
      },
    ]
  }
};

关键的一行是style-loader!css-loader?modules,它在css-loader后面加了一个查询参数modules,表示打开 CSS Modules 功能。