Css: scope和module的使用区别

382 阅读2分钟

scoped和module使用场景

用于解决样式覆盖问题

scoped

限制当前css作用域,阻止当前层css样式传递到下层

  1. 常规使用,阻止样式覆盖
<!-- 父组件  index.vue -->
<template>
  <div class="content">
    <div class="title-wrap">我是红色的</div>
    <green-title></green-title>
  </div>
</template>
 
<style lang="scss">
.content {
  .title-wrap {
    font-size: 20px;
    color: red;
  }
}
</style>


<!-- 子组件 -->
<template>
  <div class="content">
    <div class="title-wrap">我是绿色的</div>
  </div>
</template>
 
<style lang="scss">
.content {
  .title-wrap {
    font-size: 20px;
    color: green;
  }
}
</style>

运行效果:

2059834476-5c494ba53e2e1_fix732 (1).jfif

父组件覆盖子组件样式导致,使用scoped解决

<style lang="scss" scoped>
.content {
  .title-wrap {
    font-size: 20px;
    color: red;
  }
}
</style>

从css源码了解scoped实现原理:

---未添加scoped:

1652369193-5c494bf2ef070_fix732.jfif

---添加scoped:

1759770726-5c494bfc2612c_fix732.jfif

父组件class为'title-wrap'的div增加了data-v-67e6b31f的前缀, 用于区别子组件的同类名div

scoped特性:借助了PostCSS实现

使用 scoped 后,父组件的样式将不会渗透到子组件中。不过一个子组件的根节点会同时受其父组件有作用域的 CSS 和子组件有作用域的 CSS 的影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。因此子组件‘content’组件也有前缀

增加了scoped属性将父组件样式做如下转换:

<style lang="scss">
.content[data-v-67e6b31f] {
  .title-wrap[data-v-67e6b31f] {
    font-size: 20px;
    color: red;
  }
}
</style>
  1. 深度作用

用于个别样式传递到下层的需求

// 使用>>>
<style scoped>
.content >>> .title-wrap {
    font-size: 20px;
    color: red;
}
</style>

// 预处理器使用/deep/
<style lang="scss" scoped>
.content {
  /deep/ {
    .title-wrap {
      font-size: 20px;
      color: red;
    }
  }
}
</style>


//  最终样式编译结果
.content[data-v-67e6b31f] .title-wrap {
    font-size: 20px;
    color: red;
}

最终结果:

2059834476-5c494ba53e2e1_fix732 (1).jfif

module

  1. style中增加module属性。

  2. 在布局中的引用,都需要添加前缀$style。因为通过module作用的style都被保存到$style对象中。

  3. 导出style中定义的变量

<template>
  <div :class="$style.content">
    <div :class="$style['title-wrap']">我是红色的</div>
    <green-title></green-title>
  </div>
</template>
 
<style lang="scss" module>
.content {
  .title-wrap {
    font-size: 20px;
    color: red;
  }
}
</style>

//查看引用名
console.log(this.$style.content)
console.log(this.$style['title-wrap'])

css源码:

773476474-5c494c5d440e9_fix732.jfif

通过module作用的class会重新命名,命名格式如下:

组件名_类名_随机后缀 (index_title-wrap_3b0wc)

这种命名方式好处在于:

(1)大型项目中能够帮助我们迅速定位到要查找的组件

(2)可以很灵活的将任意的父组件样式传递到任意深层的子组件中

例如,将父组件中的title-wrap通过props传递到子组件中

<template>
  <div :class="$style.content">
    <div :class="$style['title-wrap']">我是红色的</div>
    <green-title :styleTitle="$style['title-wrap']"></green-title>
  </div>
</template>

<template>
  <div class="content">
    <div :class="styleTitle">我是绿色的</div>
  </div>
</template>
<script>
 
export default {
  props: {
    styleTitle: String,
  },
}
</script>

2059834476-5c494ba53e2e1_fix732 (1).jfif

导出style中定义的变量

<template>
  <div :class="$style.content">
    <div :class="$style['title-wrap']">我是红色的</div>
    <green-title :styleTitle="$style['title-wrap']"></green-title>
    <div>{{$style.titleColor}}</div>
  </div>
</template>
 
<style lang="scss" module>
$title-color: red;
:export {
  titleColor: $title-color
}
.content {
  .title-wrap {
    font-size: 20px;
    color: $title-color;
  }
}
</style>

更多module相关操作

module动态绑定class写法:

// active为动态绑定的样式
:class="[$style.label, { [$style['active']]: tabIndex === 1 }]"

优劣势对比

--scoped:

适用于中小项目

影响子组件根元素样式

--module:大项目

快速查找定位

控制style向下传递(props)

变量导出

css 模块化

解决命名冲突

(1) BEM命名规范

Block_Element_modifier: 通过命名约束解决命名冲突问题

(2) CSS Modules

动态生成class名,实现局部作用域效果

// vue中使用(vue-cli提供为vue-loader, vue-loader提供了与 CSS Modules 的集成)
<style module>   // 注入$style计算属性
<style module="a">    // 自定义注入名称
// 向组件注入一个局部对象,可在模板中动态绑定
<template>
  <p :class="$style.red">
    This should be red
  </p>
</template>


-------------
// .js
import styles from './foo.module.css'; 
element.innerHTML = `<div class="${styles.green}">`;


-------------
// .css
.green {
  color: green;
}
// 编写全局样式
:global(.green) {
  color: red;
}
// 样式复用
.otherClassName {
  composes: green;
  color: yellow;
}

配合css-loader打包使用,或者使用vue-cli(支持css modules)创建项目

(3) CSS in JS

import styled from "styled-components";
// 创建一个带样式的 h1 标签
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
`;

参考链接: Css Modules