Vue项目中CSS Modules和Scoped CSS的介绍与区别

目录
  • 背景
  • CSS Modules
    • 原理
    • 规则
    • :global选择器
    • Vue3新特性
  • Scoped CSS
    • 原理
    • 规则
    • 深度作用选择器
    • Vue3新特性
  • 二者的比较
  • 总结

背景

在前端工程化飞速发展的时候,作为非编程语言的CSS在融入模块化的浪潮时产生了很多问题:

  • 无法做到样式模块化

组件化开发是前端模块化的核心,但是原生CSS的思想是样式的层叠,对于组件来说并不友好,会造成组件样式被覆盖等问题。

于是我们希望样式是存在作用域的,即在组件的作用域内,组件样式只对该组件生效。

  • 命名混乱

在大型项目中,多人合作经常容易产生命名混乱的问题,直接后果就是代码风格不统一、样式冲突等。

  • 高重复

组件开发也意味着有很多样式代码是重复的,在项目中显得十分冗余。

于是我们希望存在一种机制可以导入和导出CSS,做到样式的复用。

解决CSS模块化的方案有很多种,在Vue项目中,Vue Loader支持的两种分别是Scoped CSS和CSS Modules。

Scoped CSS是Vue Loader默认支持的,因此在Vue项目中可以直接使用;

CSS Modules被Vue Loader视为模拟Scoped CSS的替代方案,也提供了集成来支持,但是需要写入一些配置。

// vue.config.js
// 使用vue-cli的话,可以直接在该文件中配置,不用暴露webpack的配置
​
module.exports = {
    css: {
        // 开启CSS Modules
        requireModuleExtension: true;
        loaderOptions: {
            // 向loader传递配置选项
            css: {
                modules: {
                    // 自定义类命名规则
                    // 在我们的项目中,对类的命名是根据环境不同而改变的,开发环境中会展示该类的文件路径方便调试,其他环境中会                      使用hash值封装
                    localIdentName: process.env.NODE_ENV === 'development' ? '[path][name]__[local]' :                          '[hash:base62:8]',
                }
            }
        }
    }
}

需要知道的是,这两个解决方案都不是CSS的官方规范,只是我们通过一些构建工具,比如Webpack或者脚手架来加载对应的Loader,从而对CSS代码进行一些转换,来做到实现模块化的效果。

CSS Modules

原理

CSS Modules实现CSS模块化的原理就是根据我们在config文件中定义的类名命名规则给类生成一个独一无二的命名,从而实现作用域的隔离。

  • 转化前
<style module>
.example {
  color: red;
}
</style>
​
<template>
  <div class="example">hi</div>
</template>
  • 转化后
<!-- 转化规则是自己定义的 -->
<!-- 生产环境中,直接用hash值封装 -->
<style module>
._1TdbN_VT {
  color: red;
}
</style>
​
<template>
  <div class="._1TdbN_VT">hi</div>
</template>
​
<!-- 开发环境中,会显示来源 -->
<style module>
.src-views-login-Index__example {
  color: red;
}
</style>
​
<template>
  <div class=".src-views-login-Index__example">hi</div>
</template>

规则

  • Vue项目中的使用

在style标签中需要声明module特性:

<style module>
...
</style>

声明module特性后,Vue Loader会生成一个$style计算属性,向组件注入CSS Modules对象,我们可以通过使用该计算属性在template和JS中访问到CSS Modules对象。

<template>
    <!-- 直接通过$style来访问red类,同理$style作为计算属性也支持对象和数组语法 -->
  <p :class="$style.red">
    This should be red
  </p>
</template>
  • Composition:样式的组合
.classA {
    color: green;
    background: red;
}
​
.classB {
    composes: classA;
    color: red;
}
  • 使用composes规则可以把其他类和该类的样式组合起来
  • 要注意composes声明的规则必须在自身规则之前;

    可以一次性组合多个class,类名之间用空格隔开,但是这些class都必须是local scoped的

  • Dependencies:通过导入实现依赖

如果需要组合其他module里的样式,可以通过导入的方式:

.classC {
    composes: classA from './style.css'
}
  • 要注意当组合了不同CSS文件中的不同类时,CSS Modules是默认这些类之间不存在先后顺序的,因此导入时要保证这些类之间没有规则冲突
  • 组合的类之间不能存在循环依赖
  • composes实现的原理就是通过loader把import的CSS文件处理成ICSS格式的中间件,导出一个保存了所有local类名到global类名映射的对象,实际上这也是在JS文件中直接import CSS文件的原理

:global选择器

:global()允许括号中声明的选择器命中全局,即其类名不会经过规则封装,因此不受作用域的限制。

实际项目中,当我们希望修改所使用组件库的默认样式时,在使用CSS Modules方案的情况下,就可以通过:global()来修改其默认样式,但是要注意最好外面有一层类封装,否则可能影响全局样式。

Vue3新特性

  • 自定义module命名
<style module="login">
...
</style>

支持给module命名,可以用module名替代$style,比如<div :class="login.red"></div>。

  • 组合式API中的CSS Modules

在setup()中可以使用useCssModuleAPI来获取module对象。

  • 在CSS中使用v-bind

支持在style中把某条rule的值和data中的一个数据绑定,比如:

.red {
    color: v-bind(color);
}

Scoped CSS

原理

Vue Loader默认使用CSS后处理器PostCSS来实现Scoped CSS,原理就是给声明了scoped的样式中选择器命中的元素添加一个自定义属性,再通过属性选择器实现作用域隔离样式的效果。

  • 转化前
<style module>
.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>

规则

  • 一个Vue文件中可以同时存在global和scoped的样式,即允许声明两个style标签。
<style>
/* global styles */
</style>
​
<style scoped>
/* local styles */
</style>
  • 使用Scoped CSS以后,因为样式具有了作用域,所以父组件的样式是不会影响到子组件的,即父组件和子组件的样式都具有自己的作用域。

    但是对于子组件的根元素来说,其样式还是可以受父组件控制的,使得父组件可以控制布局。

  • 注意通过v-html创建的DOM内容是不受Scoped CSS控制的,如果希望修改其中的样式,可以通过深度作用选择器。
  • 因为Scoped CSS是通过属性选择器实现的,所以最好不要和标签选择器混用,会产生性能问题。

深度作用选择器

  • 深度作用选择器使得父组件的样式可以渗透到子组件,其原理是使用后代选择器。
/* 转化前 */
<style scoped>
.a :deep(.b) {
  /* ... */
}
</style>
​
/* 转化后 */
.a[data-v-f3f3eg9] .b {
  /* ... */
}
  • 需要注意深度作用选择器和声明为global样式的区别,深度作用选择器只是为了能让父组件控制子组件样式,而global样式是全局起效的。
  • 实际项目中,当我们希望修改所使用组件库的默认样式时,在使用Scoped CSS方案的情况下,就可以通过深度作用选择器来修改其默认样式。
  • 几种深度左右选择器的写法:
    • /deep/:已废弃
    • >>>:在不使用Sass预处理器时可以使用
    • ::v-deep:使用Sass预处理器时使用

Vue3新特性

  • 深度作用选择器

    废弃/deep和>>>,使用:deep(.child-class)来替代::v-deep

  • :slotted()选择器

    支持使用:slotted(selector)来控制slot中的样式

  • :global()选择器

    当只有某些规则需要全局起效时,允许不重复声明一个全局作用域的style标签,而是使用:global(selector)来声明为全局样式。

二者的比较

CSS Modules Scoped CSS
需要在vue.config.js中额外配置 Vue Loader默认支持,无需额外配置
通过根据配置的类命名规则,为元素生成独一无二的类名来实现作用域隔离 通过给元素自定义hash属性,再使用属性选择器选中元素来实现作用域隔离
在style标签中声明module 在style标签中声明scoped
支持导入其他module的样式,支持样式组合 /
通过:global()来解除作用域的隔离,使样式在全局生效 1. 可以定义全局样式,使样式不受作用域约束;2. 可以通过深度作用选择器命中子组件,从而控制子组件的样式

总结

到此这篇关于Vue项目中CSS Modules和Scoped CSS的介绍与区别的文章就介绍到这了,更多相关Vue中CSS Modules和Scoped CSS内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 解决vue scoped scss 无效的问题

    今天遇到scoped内部的scss设置无效,解决办法如下: /deep/ <style scoped lang="scss"> .position-el-steps { /deep/ .el-step.is-vertical { .el-step__description { margin-top: -20px; } .el-step__line { border-left: 2px dashed #c0c4cc; background-color: transparent

  • Vue 中使用 CSS Modules优雅方法

    CSS Modules:局部作用域 & 模块化 CSS Modules 为每一个局部类赋予全局唯一的类名,这样组件样式间就不会相互影响了.如: /* button.css */ .button { font-size: 16px; } .mini { font-size: 12px; } 它会被转换为类似这样: /* button.css */ .button__button--d8fj3 { font-size: 16px; } .button__mini--f90jc { font-size

  • 简单明了带你了解CSS Modules

    层叠样式表 我们知道,css的全名叫做层叠样式表,这个"层叠"到底是什么意思呢? 有一种解释是,如果你先写了一条样式规则(选手1): .title { color: silver; } 然后又在后边写了一条类似的(选手2): .title { color: gold; } 因为名字相同,选手2就会和选手1打起来(让你丫冒充我!).结果是选手2获胜,class名为title的元素,最终的color值为gold. css里就像这样,随时可能一言不和就发生战争,结果输掉的一方就会被胜利的一方

  • Vue中对比scoped css和css module的区别

    scoped css 官方文档 scoped css可以直接在能跑起来的vue项目中使用. 使用方法: <style scoped> h1 { color: #f00; } </style> 使用scoped划分本地样式的结果编译结果如下: h1[data-v-4c3b6c1c] { color: #f00; } 即在元素中添加了一个唯一属性用来区分. 缺点 一.如果用户在别处定义了相同的类名,也许还是会影响到组件的样式. 二.根据css样式优先级的特性,scoped这种处理会造成

  • Vue3新特性之在Composition API中使用CSS Modules

    在 Vue 3 Composition API 最近的一次 beta 升级中,无论是 Vue 3 本 3 库 vue-next,还是面向 Vue 2 过渡用的 @vue/composition-api 库中,都同步更新了一个 useCSSModule 函数 -- 用来在使用了 Composition API 的 Vue 实例中,支持 CSS Modules 语法. 首先来看看什么是 CSS Modules: CSS Modules CSS Modules 是一种 CSS 的模块化和组合系统.vu

  • Vue项目中CSS Modules和Scoped CSS的介绍与区别

    目录 背景 CSS Modules 原理 规则 :global选择器 Vue3新特性 Scoped CSS 原理 规则 深度作用选择器 Vue3新特性 二者的比较 总结 背景 在前端工程化飞速发展的时候,作为非编程语言的CSS在融入模块化的浪潮时产生了很多问题: 无法做到样式模块化 组件化开发是前端模块化的核心,但是原生CSS的思想是样式的层叠,对于组件来说并不友好,会造成组件样式被覆盖等问题. 于是我们希望样式是存在作用域的,即在组件的作用域内,组件样式只对该组件生效. 命名混乱 在大型项目中

  • Vue项目中使用mock.js的完整步骤

    在Vue项目中使用mock.js 开发工具选择:Vscode 1. 使用命令行创建vue项目(手动选择Babel,Router,Vuex) 2. 导入element-ui(为了显示效果好一点),命令行输入 npm i element-ui -S 3.在main.js中进行引用 import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css';//样式文件一定要引入 Vue.use(ElementUI)

  • 一次VUE项目中遇到XSS攻击的实战记录

    目录 前言 发现原因 自定义过滤规则 总结 前言 随着互联网的高速发展,信息安全问题已经成为企业最为关注的焦点之一,而前端又是引发企业安全问题的高危据点.在移动互联网时代,前端人员除了传统的 XSS.CSRF 等安全问题之外,又时常遭遇网络劫持.非法调用 Hybrid API 等新型安全问题.当然,浏览器自身也在不断在进化和发展,不断引入 CSP.Same-Site Cookies 等新技术来增强安全性,但是仍存在很多潜在的威胁,这需要前端技术人员不断进行"查漏补缺". 发现原因 一切

  • Vue项目中如何运用vuex的实战记录

    目录 Vuex 是什么? vuex使用周期图 我的store目录 实现一个vuex的示例 总结 Vuex 是什么? TIP

  • 三分钟让你快速学会axios在vue项目中的基本用法(推荐!)

    目录 Axios简介 一.axios是干啥的 二.安装使用 三.Axios请求方式 1.axios可以请求的方法: 2.get请求 3.post请求 4.put和patch请求 5.delete请求 6.并发请求 四.Axios实例 1.创建axios实例 2.axios全局配置 3.axios实例配置 4.axios请求配置 五.拦截器 1.请求拦截器 2.响应拦截器 3.取消拦截 六.错误处理 七.取消请求 结语 提示:本篇详解axios在vue项目中的实例.在使用Vue.js框架开发前端项

  • VUE项目中引入JS文件的方法总结

    目录 1.在index.html页面使用script标签引入 2.在main.js中使用window.moduleName 使用 3.手动添加export 4. 使用import方式,把需要的js库中的方法挂载到全局 补充:Vue3如何引用全局JS文件 总结 在开发Vue项目的时候,有时需要使用一些非ES6格式的没有export的js库,可以有如下方法实现: 1.在index.html页面使用script标签引入 当然也可以使用cdn的地址.这样引入后的内容是全局的,可以在所有地方使用. <!D

  • Axios在vue项目中的封装步骤

    目录 1. 什么是Axios? 2. 回顾Ajax 3. 回顾Promise 4. Vue封装Axios 1. 什么是Axios? Axios 是一个基于 promise 的网络请求库,可以用于浏览器和 node.js,是一个第三方插件,第三方异步请求工具库 Axios的特点: 可以运行在浏览器和node.js环境中 基于promise,可以调用promiseAPI 默认发送的是get请求,默认post请求发送的数据格式是JSON 除了表单格式数据,对请求数据和响应数据可以自动转换JSON数据格

  • 手把手教你如何在vue项目中使用rem布局

    目录 如何在vue项目中使用rem布局 方法一:使用lib-flexible 1. 安装包 2. 引入文件 3. 根据需要设置rem 4.使用rem 方法二:使用postcss-pxtorem 1. 安装包 2. 创建rem.js文件 3. 新建 .postcssrc.js 4. 在main.js中引入 5. 设置body的font-size 6. 可参照流程图 总结 如何在vue项目中使用rem布局 场景: 在我们开发移动端项目中,实现手机页面布局,需要使用rem布局,那么该如何使用呢? 本文

  • animate.css在vue项目中的使用教程

    在vue项目中使用动画其实有多种方式,可以使用vue中的过渡transition,可以使用animate动画与transition配合使用,也可以单独使用animate动画库(详情可见vue官网-过渡:过渡),下面我们开始介绍在vue中单独使用animate动画,其实也非常简单,两步留可以实现: 第一步:安装: 在命令行中执行:npm install animate.css --save 第二步:引入及使用: main.js中: import animated from 'animate.css

  • 在vue项目中安装使用Mint-UI的方法

    一.Mint UI 是 由饿了么前端团队推出的 一个基于 Vue.js 的移动端组件库,具有以下特性: 使用文档: http://mint-ui.github.io/#!/zh-cn Mint UI 包含丰富的 CSS 和 JS 组件,能够满足日常的移动端开发需要.通过它,可以快速构建出风格统一的页面,提升开发效率. 真正意义上的按需加载组件.可以只加载声明过的组件及其样式文件,无需再纠结文件体积过大. 考虑到移动端的性能门槛,Mint UI 采用 CSS3 处理各种动效,避免浏览器进行不必要的

随机推荐