根本原因是 CSS 的全局性和层叠性;可通过 CSS Modules 实现局部作用域、Vue 的 scoped 属性限制样式范围、BEM 命名规范约束全局污染,并需团队遵守不滥用 !important 等约定。
根本原因是 CSS 的全局性和层叠性。比如你给 .header 加了 margin-bottom: 20px,但页面里所有同名类都会被影响;又或者用了通配符选择器 *、元素选择器 div、或未加命名空间的 .btn,改动就很容易“溢出”到其他区域。
在支持 CSS Modules 的构建工具(如 Webpack + css-loader?modules)中,把样式文件命名为 Button.module.css,导入后类名会被自动哈希化,避免冲突。
/* Button.module.css */
.root {
background: #007bff;
padding: 8px 16px;
}JS 中使用:
import styles from './Button.module.css';function Button() { return ; }
Button_root__kx12a,天然隔离.root?那就不该放这里):global(.header) 外部类,除非你明确想穿透scoped 属性限制 Vue 单文件组件样式Vue 的 会给模板中的每个元素自动添加唯一 data 属性,并重写 CSS 选择器,实现视觉上的局部作用域。
.container[data-v-f3f3e
g9] { ... }
scoped 样式,也不受其影响:deep(.child)(Vue 3)或 >>>(Vue 2),但这是主动穿透,不是意外泄漏没有构建工具或老项目无法上 CSS Modules 时,BEM 是最务实的防御手段:靠命名约定强制隔离语义边界。
header → site-header(加前缀防重名)site-header__logo(双下划线表示元素)site-header--fixed(双横线表示修饰符)div、span 等元素选择器,全部走类名.site-header { .site-footer { ... } } 这种写法等于埋雷真正难的不是加个 scoped 或改个文件后缀,而是团队是否坚持不写 !important、不滥用 ID 选择器、不在公共样式表里塞业务组件规则——这些细节才是隔离失效的源头。