问题描述:
PC端项目中,在本地运行样式没问题,打包后到测试环境,页面样式就出现问题,打开F12查看页面代码后可以看到加载的css顺序变化了。
而后,统一修改某个class,本地为A覆盖了B,打包后可能为B覆盖了A。
查找了很多文章和资料后,将问题定位在是因为加载css顺序不一样导致的,最后的解决方案也印证了这一点。
遇到这种问题,往往是在某个组件中,没有用scoped,导致污染了全局的样式。
因为我的现在做的项目是之前多人开发,这次问题是因为前任开发者们代码规则不严谨、css到处乱引用产生的错误。具体原因是:前任开发者们在main.js引入了element的样式,然后到单独的组件中,又引入了一遍。
css作用域
css的作用域问题,即使是模块化编程下,在对应的模块的js中import css进来,这个css仍然是全局的。导致在css中需要加上对应模块的html的id/class 使用css选择器 保证css的作用域不会变成全局 而被其它模块的css污染。
解决方法
将所有组件中引入的(因为通过@import引入或者import引入,作用域是全局)面向全局的样式,都删掉,然后统一在main.js中引入。这样全局的顺序都在main.js 中确定,同时也不要重复引用。
结果
本地和测试的样式一样。不再受打包后的影响。这个时候,再针对某些污染的样式在scoped中具体修改,如果对于element弹窗类的,需要脱离scoped,那就写成公共样式在main.js中引入。
定一个规则,公共样式中main.js引入,单独的都使用scoped属性,写在页面里面,可以通过以下方式引入。
<style scoped src="main.css"></style>
来讲讲css里的 Scoped CSS
Scoped CSS规范是Web组件产生不污染其他组件,也不被其他组件污染的CSS规范。
vue组件中的style标签标有scoped属性时表明style里的css样式只适用于当前组件元素
它是通过使用PostCSS来改变以下内容实现的:
<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>
混合使用全局属性和局部属性
<style>
/* global styles */
</style>
<style scoped>
/* local styles */
</style>
关于子组件的根元素
使用了scoped属性之后,父组件的style样式将不会渗透到子组件中,然而子组件的根节点元素会同时被设置了scoped的父css样式和设置了scoped的子css样式影响,这么设计的目的是父组件可以对子组件根元素进行布局。
在vue模板中的样式是根据需要按需加载,访问一个页面该组件中的样式就会追加到head标签中,如果父子组件中都对某个子组件根节点元素进行了控制,则父组件里的样式会被后来的覆盖。
在style加scoped后,生成一个data-v-XXXXX的唯一标识,给所在组件的父级全部加唯一标示,达到样式私有化,不污染全局的作用。
通过给 dom 增加一个动态属性,然后 css 选择器也额外添加对应的属性来选择该 dom ,达到该样式只作用于含有该属性的 dom,实现组件样式的模块化。