前言
项目上线遇到了css样式问题,经过排查发现是 main.css
中声明了两个 :root{}
,导致后一个覆盖了前一个。然而测试环境并未出现这个问题,样式效果为两个 :root {}
合并。
package.json
如下:
原因
build:test
打包结果:
build:prod
打包结果:
从 dist/index.html
观察到的不同点:
- 测试环境 (
build:test
) 没有static/css
文件,观察index.html
,CSS
是直接内联方式加载的。 - 生产环境 (
build:prod
) 生成了static/css
,即CSS
被单独提取到了CSS
文件中。
原因如下:
- CSS 代码优化策略
- Vue CLI 默认在
production
环境使用cssnano
进行 CSS 代码优化(压缩、合并、去重)。 cssnano
优化了:root{}
变量,它的策略是 合并相同的变量,如果变量相同会合并,如果有不同值,后面的会覆盖前面的。
- Vue CLI 默认在
- CSS 提取方式不同
- 测试环境可能是
inline
或通过JS
注入style
,在合并多个:root{}
时,浏览器会自动合并。 - 生产环境中
CSS
被单独提取到static/css
,并可能经过cssnano
的优化,导致:root{}
选择器的行为不同。
- 测试环境可能是
- PostCSS 处理机制
- Vue CLI 使用
postcss
处理CSS
,它可能在production
环境启用了cssnano
的mergeRules
规则,导致:root{}
合并方式发生变化。
- Vue CLI 使用
解决方式
一、测试环境开启CSS提取确保与生产环境一致
javascript
module.exports = {
css: {
extract: process.env.NODE_ENV !== 'development'
}
};
再次执行 npm run build:test
二、手动将多个:root合并
css
:root {
--color-primary: #409eff;
--color-secondary: #f56c6c;
}
:root {
--color-success: #67c23a;
--color-warning: #e6a23c;
}
手动合并为
css
:root {
--color-primary: #409eff;
--color-secondary: #f56c6c;
--color-success: #67c23a;
--color-warning: #e6a23c;
}
三、手动禁用 cssnano 相关优化
javascript
module.exports = {
css: {
extract: true, // 确保生产环境也提取 CSS
loaderOptions: {
postcss: {
plugins: [
require('cssnano')({
preset: ['default', { mergeRules: false, mergeLonghand: false }]
})
]
}
}
}
};