CSS自定义属性、:where()、@layer和BEM命名可有效隔离模块样式作用域:用--module-gap等变量统一控制设计约束;:where()限定作用范围且不增优先级;@layer声明层级避免覆盖;BEM前缀确保类名唯一。
多个布局模块共用同一份 CSS 时,margin、padding、width 等基础属性容易互相干扰。直接靠选择器优先级硬压不是长久之计,更可靠的方式是把每个模块的“设计约束”显式抽成自定义属性,在模块根元素上统一设置。
--module-gap: 16px 控制内部间距,子组件只读取该变量,不写死数值--module-max-width: 768px 替代全局 max-width,避免影响其他区域style="--module-gap: 24px; --module-max-width: 1024px;"
gap: var(--module-gap)、max-width: var(--module-max-width),天然隔离:where() 作用域前缀传统写法如 .header .nav a 容易被外部样式穿透或意外命中。CSS :where() 不增加优先级,但能精准限定作用范围,适合模块封装。
class="layout-hero"
:where(.layout-hero) > * 或 :where(.layout-hero) .button 开头.button,也不会被这个模块的规则影响:is() 更安全——它完全不参与优先级计算,彻底规避样式污染@layer 显式声明模块样式层级CSS 层叠逻辑混乱的根本原因是缺乏层级声明。现代浏览器支持的 @layer 让你可以把不同模块的样式分组归类,控制加载和覆盖顺序。
@layer layout, layout-hero, layout-features, layout-footer;
@layer layout-hero { ... }
@layer utilities,天然低于 layout 层,不会越权覆盖布局结构@layer 声明顺序决定层优先级,先声明的层优先级更低像 .title、.content 这类泛化类名,一旦多个模块同时使用,就等于主动放弃样式隔离。BEM 不是教条,关键是“模块前缀 + 语义后缀”的组合逻辑。
.title,改写 .hero__title、.features__title
.hero__cta-button,而非 .button--primary
.hero__title--large 不会干扰 .features__title--large
body 上的 font-size 被改了,三个模块的行高全乱;某个全局 box-sizing: border-box 漏写了,一个模块的宽度计算就崩。拆分不是为了多建几个文件,而是让每个模块能回答清楚:“我的尺寸、间距、字体、盒模型,由谁定义?能否被外部静默修改?”