1. 项目概述:从“写样式”到“建系统”的思维跃迁
你有没有过这样的经历:刚写完一个按钮的样式,发现另一个页面里几乎一模一样的按钮,却要重新敲一遍 background-color 、 border-radius 、 padding ?改个主色调时,满屏搜索 #4a90e2 ,生怕漏掉某个藏在角落的 .btn-primary ?或者更糟——团队协作时,同事写的 .card 和你理解的 .card 根本不是一回事,一个带阴影一个没边框,最后上线前疯狂对齐?这些不是小问题,而是 CSS 类(class)使用失当最典型的症状。 CSS 类从来不只是“加个 class 名字”这么简单;它是一套前端开发中最基础、也最容易被低估的“设计语言系统”。 今天这篇内容,不讲语法定义,不列选择器清单,而是带你回到真实项目现场,拆解“如何创建类”这件事背后的真实逻辑:为什么有的类越用越顺手,有的类越写越混乱?为什么新手照着教程写出来的类,在真实业务中三天就崩?关键不在 . 符号怎么打,而在于你创建类时,脑子里有没有一张清晰的“责任地图”——这个类管颜色?管布局?管状态?还是管皮肤?我干了十多年前端,带过二十多个项目,踩过最多坑的地方,恰恰就是这个看似最简单的 .class 。它不像 JavaScript 那样有报错提示,也不像 HTML 那样结构一目了然;它的坏味道是静默的:样式冲突、难以复用、维护成本指数级上升。所以,这篇文章不是教你怎么写 class="header" ,而是告诉你:当你在 HTML 里敲下第一个 class= 的时候,你其实在做一次小型架构决策。它决定了后续十页代码的可读性,决定了设计师改稿时你改几行,决定了三年后新同事接手时是笑着点开文件,还是默默打开辞职信。
2. 类的设计哲学:三层责任模型与命名铁律
2.1 为什么“语义化命名”是个伪命题?
很多教程一上来就强调“用语义化命名”,比如 .article-title 而不是 .red-big-text 。这话没错,但只说对了一半,甚至可能误导新手。我在给某电商后台重构时就吃过亏:当时严格遵循“语义化”,把所有标题都叫 .product-name 、 .order-status 。结果产品突然要求在订单列表页,把“订单状态”文字改成和“商品名称”完全一致的字体大小、颜色、行高——因为视觉上要形成统一的信息流节奏。我翻遍 CSS,发现 .order-status 里硬编码了 font-size: 14px; color: #666; ,而 .product-name 是 16px 和 #333 。改一个?那整个订单详情页的“状态”就全乱了。最后只能加个丑陋的 .order-status--compact 覆盖,代码里全是 !important 。问题出在哪?不是命名不语义,而是我把“视觉表现”和“业务含义”混在了一个类里。真正的分层,不是“语义 vs 表现”,而是 “职责分层” :一个类,只能承担一种稳定不变的责任。我后来总结出三层铁律,现在所有团队都强制执行:
-
第一层:基础原子类(Atoms)
只负责单一、不可再分的视觉属性。比如.text-lg(仅控制font-size: 1.125rem)、.bg-blue-500(仅控制background-color: #3b82f6)、.p-4(仅控制padding: 1rem)。它们像乐高积木,本身没有意义,组合起来才有价值。这类类名必须是“描述性”的,直接对应 CSS 属性值,不掺杂业务逻辑。为什么?因为设计系统升级时,你只需要改.bg-blue-500的色值,所有用到它的地方自动更新,零风险。 -
第二层:组件类(Molecules)
封装一个完整 UI 单元的默认外观与结构,但 不绑定具体业务语境 。比如.card、.button、.input-field。它们内部可以组合原子类(.card { @apply p-4 bg-white rounded-lg shadow-sm; }),但绝不出现.card-product或.button-primary这种业务耦合名。.button的职责是定义“按钮长什么样”,至于它是“提交订单”还是“删除草稿”,那是 HTML 里data-action或 JS 逻辑的事。这样做的好处是:当产品说“所有按钮圆角从 4px 改成 6px”,你只改.button一行border-radius,全站生效。 -
第三层:场景类(Organisms)
描述组件在特定业务上下文中的行为或状态, 永远不单独使用,只与组件类组合 。比如.button--loading(按钮加载态)、.card--featured(首页推荐卡片)、.input-field--error(表单错误态)。注意双横线--是 BEM 规范的明确信号,表示这是修饰符。它的存在不是为了“看起来不同”,而是为了表达“此时此地,这个组件需要临时改变某种行为”。比如.button--loading会禁用点击、加旋转动画、变灰,但它不能改变.button的基础 padding 或 font-size——那属于第二层的职责。
提示:新手最容易犯的错,是把三层混在一起写。比如
.user-profile-card—— 它既是业务语境(user-profile),又是组件(card),还隐含了视觉(profile 常带头像+简介)。这种类一旦写出来,就注定无法复用。下次你要在后台管理页放个“管理员信息卡”,是再写个.admin-profile-card?还是强行复用?都不优雅。正确做法是:HTML 里写<div class="card user-profile">,CSS 里.user-profile { @apply flex items-center gap-3; },职责清晰,组合自由。
2.2 命名不是艺术,是工程约束
命名规则不是为了好看,而是为了降低认知负荷和协作成本。我们团队强制执行三条红线:
-
禁止驼峰式(camelCase)和下划线(snake_case) :全部用短横线(kebab-case)。原因很实际:HTML 属性名不支持驼峰(
class="userProfile"在 DOM 中会被转成小写),下划线在某些老版本 CSS 预处理器里有歧义。.nav-item-active比.navItemActive或.nav_item_active更安全、更易读。 -
禁止数字开头或纯数字类名 :
.1col、.2x看似简洁,但 IDE 自动补全时会排在最前面,干扰搜索;更重要的是,它违反了“类名应表达意图”的原则。.grid-col-1或.w-1/2(Tailwind 风格)才明确表达了“占一列”或“宽度一半”。 -
禁止“魔法数字”类名 :
.m5(margin: 5px)、.p10(padding: 10px)看似高效,实则灾难。当设计规范从5px改成6px,你得全局替换所有.m5

758

被折叠的 条评论
为什么被折叠?



