css modules和scoped区别

一、css modules是什么?

A CSS Moduleis a CSS file in which all class names and animation names are scoped locally by default. All URLs ( url(...)) and @importsare in module request format ( ./xxxand ../xxxmeans relative, xxxand xxx/yyymeans in modules folder, i. e. in node_modules).

CSS模块是一个CSS文件,默认状况下,全部类名和动画名都在本地做用域内。全部URL(url(...))@imports均以模块请求格式表示(./ xxx../ xxx表示相对,xxxxxx / yyy表示模块文件夹,即在“ node_modules”中)。css

也就是说,css modules是主要为了解决样式冲突问题,使得css样式具备做用域。html

二、vue项目中css modules和scoped区别?

vue项目中有两种解决css冲突的方案,一种是比较常见的使用scoped。另外一种就是css modules。先对这两种方案原理作一个简单介绍,而后比较他们之间的区别:vue

scoped方案

这是在vue项目中很是常见的解决样式冲突方式,当在style标签中加上scoped,编译后会在该vue组件元素上加上hash标识属性,在vue组件里的每一个元素都有同一个hash标识属性。没法彻底避开css权重和类名重复的问题。
image.pngnode

实例算法

<style scoped> 
.example { 
    color: red; 
} 
</style>  
<template>  
    <div class="example">hi</div>  
</template>

编译后数组

<style> 
.example[data-v-f3f3eg9] 
{ 
    color: red; 
} 
</style> 
<template> 
    <div class="example" data-v-f3f3eg9>hi</div> 
</template>
css modules方案

产生局部做用域的惟一方法,就是使用一个独一无二的class的名字,为全部类名从新生成类名,有效避开了css权重和类名重复的问题,这就是 CSS Modules 的作法。css module直接替换了类名,排除了用户设置类名影响组件样式的可能性sass

实例安全

<style module> 
.red { 
    color: red; 
} 
</style>  
<template>  
    // 构建工具会将类名`style.red`编译成一个哈希字符串,这样一来,这个类名就变成独一无二了,只对对应组件有效。
    <p :class="$style.red"> This should be red </p>  
</template>

编译后app

<style module>
._1yZGjg0pYkMbaHPr4wT6P__1 { 
    color: red; 
} 
</style> 
<template> 
    <p class="_1yZGjg0pYkMbaHPr4wT6P__1"> This should be red </p> 
</template>
两种方案的区别
  • scoped方案在其余地方使用相同类名可能仍是会影响组件样式,若是你子组件的某元素上有一个类已经在这个父组件中定义过了,那么这个父组件的样式就会泄露到子组件中。可是css modules方案经过算法计算出惟一类名替换原始类名避免了这种样式冲突。
//Father.vue
<template>
  <div>
    <son></son>
  </div>
</template>

<script>
import Son from './Son'
export default {
  name: 'Father',
  components: {
    Son
  },
  data () {
    return {}
  }
}
</script>

<style scoped>
.wrapper {
  width: 300px;
  height: 300px;
  line-height: 300px;
  vertical-align: middle;
  background-color: #000;
  color: #fff;
}
</style>
// Son.vue
<template>
  <div class="wrapper">111111</div>
</template>

<script>
export default {
  name: 'Son',
  data () {
    return {}
  }
}
</script>

Father组件的wrapper样式会渗透到Son组件中并起做用
image.png!工具

  • 还有一些状况是咱们须要对咱们的子组件的深层结构设置样式——虽然这种作法并不受推荐且应该避免。为了简便起见,咱们假设咱们的父组件如今要对子组件设置样式,在 scoped 样式中,这种状况可使用 >>> 链接符(或者 /deep/ )实现。但是别忘记,咱们却所以失去了组件的封装效果。这个组件内的全部的被父组件深度选择器选择的类的样式都会被浸染——即使是孙节点。而css modules方案下全部的 CSS 类能够经过$style对象获取到,因此咱们能够经过 props 将这些类传递到任何咱们但愿的深度中,这样,在子组件中的任意位置使用这些类就会变得极其容易
// Father.vue
<template>
  <div>
    <son :contentClass="$style.content"></son>
  </div>
</template>

<script>
import Son from './Son'
export default {
  name: 'Father',
  components: {
    Son
  },
  data () {
    return {}
  }
}
</script>

<style lang="scss" module>
.content {
  color: blue;
}
</style>
// Son.vue
<template>
  <div :class="$style.wrapper">
    <span :class="contentClass">111111</span>
  </div>
</template>

<script>
export default {
  name: 'Son',
  props: ['contentClass'],
  data () {
    return {}
  }
}
</script>

<style lang="scss" module>
.wrapper {
  width: 300px;
  height: 300px;
  line-height: 300px;
  vertical-align: middle;
  background-color: #000;
  color: #fff;
}
</style>

效果:

image.png

  • scoped会使标签选择器渲染变慢不少倍,而使用class或id则不会。
  • 模块式 CSS 与 JS 有着很好的互操做性 (interoperability),这一点不仅局限于 CSS 类。

三、css modules如何使用?

{
    test: /\.(sc|sa|c)ss$/,
    include: [path.join(__dirname, '.././', 'src')],
    // 匹配规则时,只使用第一匹配的数组
    oneOf: [
      // 这里匹配 `<style module>`
      {
        // 与资源查询匹配的条件
        resourceQuery: /module/,
        use: [
          // module须要使用vue-style-loader
          'vue-style-loader',
          {
            loader: 'css-loader',
            options: {
              // 开启 CSS Modules
              modules: true,
              // 自定义生成的类名
              localIdentName: '[name]_[local]_[hash:base64:5]'
            }
          },
          'sass-loader'
        ]
      },
      // 这里匹配普通的 `<style>` 或 `<style scoped>`
      {
        use: [
          // scoped使用style-loader
          'style-loader',
          'css-loader',
          'sass-loader'
        ]
      }
    ]
}

四、总结

其实两种方案都很是简单、易用,在某种程度上解决的是一样的问题。 那么你该选择哪一种呢?

scoped 样式的使用不须要额外的知识,给人温馨的感受。它所存在的局限,也正是它的使用简单的缘由。它能够用于支持小型到中型的应用。

在更大的应用或更复杂的场景中,这个时候,对于 CSS 的运用,咱们就会但愿它更加显式,拥有更多的控制权。虽然在模板中大量使用 $style 看起来并不那么“性感”,但却更加安全和灵活,为此咱们只需付出微小的代价。还有一个好处就是咱们能够用 JS 获取到咱们定义的一些变量(如色彩值、样式断点),这样咱们就无需手动保持其在多个文件中同步。

参考:
https://juejin.im/post/5b9556...
https://www.jianshu.com/p/255...
http://www.ruanyifeng.com/blo...