电商系统前后端样式治理规范

定位:适用于电商及类似动态化系统的前后端样式分层设计规范,提供决策框架、接口契约、实施路径与自检清单。


一、问题陈述

1.1 现象

架构的电商系统中,后端 Java 代码逐渐承载了越来越多的 CSS 属性——颜色值、字号、间距、圆角、甚至 marginpaddinglineHeight 被搬进 VO 对象,通过 API 下发给前端。典型表现:

  • 后端 VO 字段与 CSS 属性 1:1 镜像(如 ComponentStyle 含 19 个 CSS 属性字段)
  • 配置中心堆砌数十个样式配置键,暗黑模式使配置键翻倍
  • 后端 Java 代码中出现硬编码像素值(如 height: "6", marginLeft: "0 0 0 2"
  • 色值散落在多个 Java 类的默认值中,缺乏统一设计系统约束

1.2 根因

根因 表现 本质
运营需要动态调色 色值通过配置中心下发 合理需求,但实现方式越界
A/B 实验需要切换样式 整个 CSS 对象下发 混淆了"值"与"规则"
大促需要一键换肤 配置键随场景线性增长 缺乏令牌抽象
暗黑模式适配 配置键翻倍 前端主题系统缺位
前后端职责模糊 布局属性也由后端下发 缺乏分层规范

1.3 核心矛盾

后端需要控制"设计决策"的值,前端需要控制"设计实现"的规则。两者混在一起,导致后端成了 CSS 容器,前端成了无脑渲染器。


二、设计原则

原则一:值可下,规不下

概念 定义 归属 示例
设计决策的原子数据 后端下发 #FF0F234pxsm
设计实现的 CSS 规则 前端自主 margin-left: 8pxdisplay: flex

判断方法:把属性值替换为另一个合法值,如果 UI 语义不变则属于"规",如果 UI 语义改变则属于"值"。

  • color: #FF0F23 → 改为 #000000,UI 语义从"价格红"变为"黑色" →
  • margin-left: 8px → 改为 12px,UI 语义不变(只是间距微调) →
  • border-radius: 4px → 改为 8px,UI 语义从"小圆角"变为"大圆角" → (刻度变化)

原则二:令牌桥接,而非属性透传

后端不下发 CSS 属性名,而是下发语义令牌。前端通过 CSS 变量层消费令牌。

❌ 当前:后端 → { color: "#FF0F23", fontSize: "14", margin: "0 0 0 2" } → 前端直接绑定 style
✅ 规范:后端 → { tokens: { "price-main": "#FF0F23", "price-size": "sm" } } → 前端 CSS 变量映射 → 组件消费

原则三:主题前端解,不靠配置翻倍

暗黑模式、品牌换肤等主题切换,由前端 CSS 变量 + 媒体查询 / 属性选择器实现,后端只下发令牌值集。

原则四:设计系统单一信源

所有色值、间距刻度、字号刻度的原始定义,来源于设计系统(Design System),后端配置中心是信源的下游消费者,不是信源本身。


三、决策框架

3.1 属性归属决策树

CSS 属性归属判断

运营是否需要
动态调整该值?

是否与设备/
平台相关?

是'值'还是'规'?

🟢 前端自主
布局/动画/适配

是否属于
设计刻度?

🔴 后端下发
语义令牌

3.2 三区分类表

🔴 红区 — 后端下发(设计决策的值)
类别 典型属性 下发形式 变更驱动
品牌色/业务色 主价格色、促销色、标签色 语义令牌 price-main: #FF0F23 运营/A/B实验
语义色 成功色、警告色、错误色 语义令牌 color-success: #07C160 设计规范
间距刻度 卡片圆角、按钮圆角 刻度令牌 radius-md: 8px 设计规范
字号刻度 标题字号、正文字号 刻度令牌 font-size-title: 18px 设计规范
图标资源 图标 URL、插画 URL URL 字符串 运营/设计
文案 按钮文案、提示文案 字符串 运营/法务
🟢 绿区 — 前端自主(设计实现的规则)
类别 典型属性 理由
布局策略 display, flex-direction, grid-template, position 设备/屏幕相关
组件间距 margin, padding, gap 组件内部自治
尺寸计算 width, height, min-height, max-width 设备 DPI 相关
排版规则 line-height, text-overflow, white-space, word-break 排版是前端专长
动画效果 transition, animation, transform 性能相关
响应式 @media, container-query 屏幕相关
安全区域 safe-area-inset-* 设备相关
字体栈 font-family 平台相关(iOS/Android 字体不同)
交互状态 :hover, :active, :focus, :disabled 交互相关
加载态 骨架屏、占位符、shimmer 加载体验
🟡 黄区 — 协商决定(需根据业务场景判断)
类别 服务端角色 前端角色 协商策略
楼层容器间距 下发间距刻度(如 spacing-md 自主决定具体像素值 刻度下发,像素前端算
容器圆角 下发圆角刻度(如 radius-lg 自主决定组件内部圆角 大圆角下发,小圆角前端
字号 下发字号刻度(如 font-size-sm 根据 DPI 缩放 基准下发,缩放前端
弹层高度 下发高度比例(如 75% 自主决定最小/最大高度 比例下发,边界前端
截断行数 一般不下发 自主决定 除非运营需要动态控制

四、令牌架构规范

4.1 三层令牌模型

别名引用

别名引用

Layer 3: Component Tokens
组件消费令牌

price-label.color
→ price-main-color

price-label.fontSize
→ font-size-md

tag-danger.background
→ tag-danger-bg

card.borderRadius
→ card-radius

card.padding
→ spacing-card

Layer 2: Semantic Tokens
语义意图令牌

price-main-color
→ color-red-500

price-second-color
→ color-gray-400

tag-danger-bg
→ color-red-500

tag-success-bg
→ color-green-500

card-radius
→ radius-md

button-radius
→ radius-sm

spacing-card
→ dimension-md

Layer 1: Global Tokens
全局原始令牌

color-red-500
#FF0F23

color-gray-400
#888B94

color-green-500
#07C160

dimension-xs
4px

dimension-sm
8px

dimension-md
12px

dimension-lg
16px

radius-sm
4px

radius-md
8px

radius-lg
12px

层级职责

层级 定义者 消费者 变更频率 示例
Global 设计系统 语义层 低(设计规范升级时) color-red-500: #FF0F23
Semantic 设计系统 + 运营 组件层 中(运营调整时) price-main-color: {color-red-500}
Component 前端组件 CSS 变量 低(组件重构时) price-label.color: {price-main-color}

关键约束

  • 组件不直接引用 Global 令牌,必须通过 Semantic 令牌间接引用
  • 后端只下发 Semantic 令牌,不下发 Global 令牌,不下发 Component 令牌
  • 前端 CSS 变量层对应 Component 令牌

4.2 令牌类型定义

令牌类型 $type 值格式 示例
颜色 color HEX / RGB / RGBA #FF0F23
尺寸 dimension 数值 + 单位 8px, 0.5rem
字号 fontSize 数值 + 单位 14px
字重 fontWeight 数值 / 关键字 400, bold
圆角 borderRadius 数值 + 单位 4px
间距 spacing 数值 + 单位 8px
阴影 shadow CSS shadow 值 0 2px 4px rgba(0,0,0,0.1)
时间 duration 数值 + 单位 200ms

4.3 后端下发接口规范

请求
GET /api/wareId=xxx&theme=auto
响应(令牌区)
{
  "tokenSet": {
    "price-main-color": "#FF0F23",
    "price-second-color": "#888B94",
    "price-main-bg-color": "#FF0F23",
    "price-main-text-color": "#FFFFFF",
    "tag-danger-bg": "#FF0F23",
    "tag-danger-text": "#FFFFFF",
    "tag-success-bg": "#07C160",
    "tag-success-text": "#FFFFFF",
    "card-radius": "8px",
    "button-radius": "4px",
    "spacing-card": "12px"
  },
  "tokenSetDark": {
    "price-main-color": "#FF6B6B",
    "price-second-color": "#AAAAAA",
    "price-main-bg-color": "#FF6B6B",
    "card-radius": "8px"
  }
}

规范约束

  • tokenSet:亮色令牌集(必填)
  • tokenSetDark:暗色令牌集(可选,仅包含与亮色不同的令牌)
  • 令牌名使用 kebab-case 命名
  • 令牌值只包含,不包含 CSS 属性名
  • 不下发布局属性(margin/padding/height/width/lineHeight 等)
前端消费
/* Step 1: 注入令牌到 CSS 变量 */
:root {
  /* 由 JS 将 tokenSet 注入 */
  --price-main-color: #FF0F23;
  --price-second-color: #888B94;
  --card-radius: 8px;
}

/* Step 2: 暗黑模式覆盖(由 JS 将 tokenSetDark 注入) */
@media (prefers-color-scheme: dark) {
  :root {
    --price-main-color: #FF6B6B;
    --price-second-color: #AAAAAA;
  }
}

/* Step 3: 组件消费令牌 */
.price-label {
  color: var(--price-main-color);
  font-size: 14px;           /* 前端自主,不从后端下发 */
  line-height: 1.4;          /* 前端自主 */
  margin-left: 8px;          /* 前端自主 */
}

.card {
  border-radius: var(--card-radius);
  padding: 12px;             /* 前端自主 */
  background: var(--card-bg, #FFFFFF);  /* 令牌 + 兜底值 */
}

Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐