“基类 修饰类”是 CSS 工程化中最经典、最优雅的命名与组织模式。它源自BEMBlock Element Modifier方法论但在 Vue 3 组件化开发中被发挥到了极致。你可以把这种模式理解为“乐高积木设计法”基类Base定义一块积木的“通用骨架”尺寸、字体、基础颜色。修饰类Modifier定义这块积木的“特定皮肤”或“特殊状态”颜色变红、尺寸变大、是否禁用。这样做最大的好处是永远不需要写重复的样式代码一个类只干一件事。一、命名规范BEM 标准写法在 CSS 中我们通常用-和--来区分类型命名格式示例含义基类Block.block.btn按钮的基础样式宽高、内边距、边框圆角修饰类Modifier.block--modifier.btn--primary.btn--large主题色变为主色尺寸变大状态类State.is-状态或.block.is-状态.is-disabled.is-active临时状态禁用、激活中通常配合 JS 控制二、原生 CSS 中的写法如何组合假设我们要做一个按钮组件!-- 1. 只写基类默认灰色普通按钮 -- button classbtn默认按钮/button !-- 2. 基类 修饰类变成蓝色大按钮 -- button classbtn btn--primary btn--large主要大按钮/button !-- 3. 基类 状态类变成禁用状态 -- button classbtn is-disabled disabled禁用按钮/button对应的 CSS 代码利用层叠覆盖/* 基类定义所有按钮共有的骨架 */ .btn { display: inline-block; padding: 8px 16px; font-size: 14px; border-radius: 4px; border: 1px solid #dcdfe6; background: #fff; color: #606266; cursor: pointer; transition: all 0.3s; } /* 修饰类只改颜色基类里有的属性覆盖掉即可 */ .btn--primary { background: #409eff; border-color: #409eff; color: #fff; } /* 修饰类只改尺寸 */ .btn--large { padding: 12px 24px; font-size: 16px; } /* 状态类只改交互反馈 */ .is-disabled { opacity: 0.6; cursor: not-allowed; pointer-events: none; /* 禁止点击事件 */ }三、 Vue 3 中的最佳实践动态绑定修饰类在 Vue 中你极少会在模板里硬编码写死classbtn btn--primary因为这样就失去响应式意义了。正确做法是利用:class动态绑定将修饰类与组件的props或响应式状态关联起来。1. 封装一个通用的BaseButton.vue组件这是你在 Vite 项目中实际会写的代码!-- src/components/BaseButton.vue -- template button classbtn :class[ btn--${type}, // 动态主题primary / success / warning { is-disabled: disabled, [btn--${size}]: size // 动态尺寸large / small } ] :disableddisabled slot / /button /template script setup langts // 定义组件的 API让父组件通过传参来控制样式 type ButtonType default | primary | success | warning; type ButtonSize default | large | small; const props withDefaults(defineProps{ type?: ButtonType; size?: ButtonSize; disabled?: boolean; }(), { type: default, size: default, disabled: false, }); /script style scoped /* 基类 */ .btn { padding: 8px 16px; font-size: 14px; border-radius: 4px; border: 1px solid transparent; cursor: pointer; transition: all 0.3s; /* 默认样式default */ background: #fff; border-color: #dcdfe6; color: #606266; } .btn:hover:not(.is-disabled) { opacity: 0.8; } /* 修饰类主题 */ .btn--primary { background: #409eff; border-color: #409eff; color: #fff; } .btn--success { background: #67c23a; border-color: #67c23a; color: #fff; } .btn--warning { background: #e6a23c; border-color: #e6a23c; color: #fff; } /* 修饰类尺寸 */ .btn--large { padding: 12px 24px; font-size: 16px; } .btn--small { padding: 6px 12px; font-size: 12px; } /* 状态类 */ .is-disabled { opacity: 0.6; cursor: not-allowed; } /style2. 父组件中使用干净得像写 HTML 属性template !-- 默认灰色 -- BaseButton提交/BaseButton !-- 主要蓝色大号 -- BaseButton typeprimary sizelarge提交/BaseButton !-- 警告色禁用 -- BaseButton typewarning disabled已过期/BaseButton /template四、配合 CSS 预处理器SCSS的进阶写法如果你在 Vite 中安装了sasspnpm add -D sass可以用 SCSS 的父选择器语法让修饰类嵌套在基类内部逻辑更集中.btn { padding: 8px 16px; // ... // 使用 代表 .btn生成 .btn--primary --primary { background: #409eff; color: #fff; } --large { padding: 12px 24px; } // 状态类也嵌套进去生成 .btn.is-disabled .is-disabled { opacity: 0.6; cursor: not-allowed; } }五、基类 修饰类 vs 原子化 CSSTailwind既然你是 Vite 项目可能会听到“Tailwind CSS原子类”。这两种模式不冲突而是互补模式基类 修饰类BEM原子化 CSSTailwind写法.btn--primary { background: blue; }classbg-blue-500优点逻辑清晰语义强适合组件库内部开发极快不用想类名适合业务页面缺点需要频繁在 HTML 和 CSS 间切换类名太长可读性依赖工具提示大厂最佳实践Vue 3 生态组件内部如 Element Plus / Naive UI用基类修饰类提供语义化的type/sizeProps。业务页面App.vue 或具体页面用原子类配合unocss或tailwind快速搭建布局。给你一个无敌的“避坑原则”永远不要在基类里写死.btn { color: red; }把颜色留给修饰类。状态类.is-*不要单独使用必须配合基类一起出现classbtn is-disabled因为 CSS 权重靠组合提升。修饰类只覆盖基类中已有的属性如果基类没写border-radius修饰类里也不要写除非你想新增特性。现在你可以在你的 Vite 项目里试着封装一个BaseButton了把之前学的transition、:hover、box-sizing都结合进去。封装完这个组件你对 CSS 模块化的理解直接上一个台阶。接下来想学transition过渡动画让按钮渐变消失/出现还是想攻克position定位做吸顶导航、浮动客服按钮你来挑。