16. 样式规范与主题定制
前端手册样式规范大约 6 分钟约 1801 字
一句话定位
全站视觉由 src/theme/ 一套 SCSS + CSS 变量治理;业务页面只写结构,不写颜色 —— 记住「只用 CSS 变量」这条铁律就够了。
目录与加载顺序
代码位置:src/theme/index.scss(main.ts 里 import '/@/theme/index.scss')
theme/index.scss 引入顺序(顺序即优先级,不可随意调换)
├─ element-plus/dist/index.css ① 组件库原生样式(必须最先)
├─ app.scss ② :root 变量、滚动条、布局骨架、--next-* 变量表
├─ common/transition.scss ③ 过渡动画
├─ other.scss ④ 第三方库微调(wangeditor、vxe 滚动条、lang-flag ...)
├─ element.scss ⑤ Element Plus 组件外观覆盖
├─ page.scss ⑥ 页面级通用类(.card-header / .full-table / .detail-item)
├─ media/media.scss ⑦ 响应式(login/error/layout/form/dialog/chart ...)
├─ waves.scss ⑧ 按钮水波纹
├─ dark.scss ⑨ 暗色模式 [data-theme='dark']
├─ iconfont/xxx.scss ⑩ 阿里图标
├─ font-awesome/xxx.scss ⑪ Font Awesome
├─ vxeTable.scss ⑫ vxe 表格样式
├─ tableImage.scss ⑬ 表格内图片
├─ remix-icon/remixicon.css ⑭ Remix 图标
└─ themeTransition.scss ⑮ 主题切换过渡动画注意:
vxe-table/lib/style.css没有单独引入,样式已合并进theme/vxeTable.scss。
CSS 变量全表
项目变量 --next-*(定义在 theme/app.scss 的 :root)
| 变量 | 默认值 | 用途 |
|---|---|---|
--next-color-white | #ffffff | 纯白 |
--next-bg-main-color | #fafbfc | 主背景(html/body) |
--next-bg-color | #f5f5ff | 次级背景 |
--next-border-color-light | #f1f2f3 | 浅分隔线 |
--next-color-primary-lighter | #ecf5ff | 主色浅底 |
--next-color-success-lighter | #f0f9eb | 成功浅底 |
--next-color-warning-lighter | #fdf6ec | 警告浅底 |
--next-color-danger-lighter | #fef0f0 | 危险浅底 |
--next-color-dark-hover | #0000001a | hover 遮罩 |
--next-color-menu-hover | rgba(0,0,0,.2) | 菜单 hover |
--next-color-user-hover | rgba(0,0,0,.04) | 用户区 hover |
--next-color-seting-main/aside/header | #e9eef3 / #d3dce6 / #b3c0d1 | 布局配置预览 |
--next-gap-xs/sm/md/lg/xl | 4 / 8 / 12 / 16 / 24 px | 统一间距,不要写魔法数字 |
--next-radius-sm/md/lg | 6 / 10 / 14 px | 统一圆角 |
--next-shadow-card | 0 1px 2px rgb(0 21 41 / 4%) | 卡片常态阴影 |
--next-shadow-hover | 0 6px 20px rgb(0 21 41 / 10%) | 卡片 hover 阴影 |
--next-topbar-height | 50px | 顶栏高度 |
--next-logo-height | 50px | Logo 高度 |
--next-tagsview-height | 34px | 标签栏高度 |
--next-widget-height | 300px | 通用卡片高度 |
--next-search-control-width | 171px | 查询区控件宽度(见 App.vue) |
--next-accent-1..10 | 蓝/青/紫/橙/玫红/绿/靛/金/墨绿/亮蓝 | 强调色板,统计卡、图表、图标底色共用 |
--next-accent-N 具体值:
1 #5b8def 蓝 2 #5fa8b8 青 3 #8b7cd8 紫 4 #e08a5b 橙 5 #d47b8e 玫红
6 #7aa86b 绿 7 #7d7fc4 靛 8 #c99a5b 金 9 #5f9e8f 墨绿 10 #62b2f7 亮蓝Element Plus 变量(在 :root 中被项目改写)
| 变量 | 值 | 说明 |
|---|---|---|
--el-text-color-regular | rgba(0,0,0,.88) | 正文色降一档,接近成熟产品灰度 |
--el-card-border-radius | 10px | 全站卡片圆角 |
--el-card-border-color | var(--el-border-color-lighter) | 卡片边框 |
--el-border-radius-base | 6px | 按钮/输入框/标签基础圆角 |
--el-dialog-border-radius | 10px | 弹窗圆角 |
--vxe-primary-lighten-color / --vxe-primary-darken-color | var(--el-color-primary) | vxe 跟随主色 |
主色
--el-color-primary由stores/themeConfig.ts的themeConfig.primary(默认#248067)在运行时注入,不要在 SCSS 里写死。
页面级通用类(theme/page.scss)
| 类 | 作用 | 用法 |
|---|---|---|
.card-header | flex 两端对齐 + 自动换行 + 8px gap | <template #header><div class="card-header">…</div></template> |
.full-table | flex: 1 且 .el-card__body 撑满(关键是 min-height: 0 的 flex 收缩) | <el-card class="full-table"> |
.detail-item | 键值排版:左侧 label 96px、右侧 value 自适应 | <div class="detail-item"><span class="detail-label">…</span><span class="detail-value">…</span></div> |
.el-descriptions | 描述列表 label 底纹、字重 | 直接用组件即可 |
.el-dialog__footer / .el-drawer__footer | 统一 padding: 12px 16px + 顶部 1px 分隔线 | 自动生效 |
.el-table th | 表头浅底(color-mix 主色 5%)+ 加粗 | 自动生效 |
pre | 日志/JSON 正文:pre-wrap + 断词 + margin: 0 | v-html 渲染日志时自动生效 |
示例:
<el-card shadow="hover">
<template #header>
<div class="card-header">
<span>基本信息</span>
<el-button type="primary" text>编辑</el-button>
</div>
</template>
<div class="detail-item">
<span class="detail-label">创建人</span>
<span class="detail-value">{{ row.createUserName }}</span>
</div>
</el-card>暗色模式
- 开关:
stores/themeConfig.ts的themeConfig.isIsDark,切换时给document.documentElement加data-theme="dark"。 - 变量覆盖集中在
theme/dark.scss的[data-theme='dark']块:先重定义--next-bg-main等基础色,再用!important把--el-*重绑到暗色值。 - 因为组件都读变量,业务页面零改动即可跟随暗色。
- 第三方库(wangeditor)在
other.scss里用[data-theme='dark']覆盖它的 CSS 变量。
// theme/dark.scss(节选)
[data-theme='dark'] {
--next-bg-main: #101b2e;
--next-color-disabled: #111f33;
--next-color-bar: #dadada;
--next-bg-main-color: var(--next-bg-main) !important;
--el-text-color-primary: var(--next-color-bar) !important;
--el-border-color: var(--next-border-black) !important;
}改组件外观的正确姿势
按优先级从高到低:
- 优先用组件属性 / 主题配置
shadow="never"、size="small"、themeConfig.primary等,能不动 CSS 就不动。 - 页面内 scoped 覆盖(推荐)
<style scoped lang="scss"> .my-table { :deep(.vxe-header--row) { background: var(--next-bg-color); } } </style>scoped自带属性选择器,优先级天然高于page.scss的全局类,可以直接压过。 - 全局统一观感 → 改
theme/page.scss只写「通用结构类」与组件外观微调,不出现任何业务选择器。 - 新增全局变量 → 改
theme/app.scss的:root并在暗色模式里同步覆盖。
❌ 不要做:写裸色值、写 !important 硬压、把业务选择器塞进全局样式文件。
响应式栅格约定
查询区统一四列响应式(项目内已成惯例):
<el-col class="mb5" :xs="24" :sm="12" :md="8" :lg="6" :xl="6">| 断点 | xs | sm | md | lg | xl |
|---|---|---|---|---|---|
| 一行几列 | 1 | 2 | 3 | 4 | 4 |
表单区(弹窗内)常用两列:
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">工具类:mb5(5px 下边距,查询区)、mb20(20px 下边距,表单区)、w100(宽 100%)。
示例:一个符合规范的页面样式块
<style scoped lang="scss">
.sys-demo-container {
display: flex;
flex-direction: column;
height: 100%;
gap: var(--next-gap-sm); // ✅ 用间距变量
.stat-card {
padding: var(--next-gap-lg);
border-radius: var(--next-radius-md);
box-shadow: var(--next-shadow-card);
border-left: 3px solid var(--next-accent-1); // ✅ 用强调色变量
transition: box-shadow 0.2s ease;
&:hover { box-shadow: var(--next-shadow-hover); }
}
:deep(.el-card__body) {
padding: var(--next-gap-md);
}
}
</style>⚠️ 注意事项 / 禁止事项
- 禁止裸色值:
#5b8def、rgb(0,0,0)一律改成var(--next-accent-N)/var(--el-*)。唯一的例外是mask、rgba(..., 0.x)这类需要透明度的遮罩,但也必须走变量组合。 - 禁止
!important:项目里!important只出现在theme/全局层(且有限)。业务页出现!important基本意味着选择器写错了 —— 用scoped+:deep()提高优先级。 - 禁止业务选择器进全局:
page.scss/app.scss里不允许出现.sys-demo-xxx这类类名。 - 禁止写死布局高度:
calc(100vh - 50px)改成calc(100vh - var(--next-topbar-height))。 - 禁止在业务页重定义
--el-*:会污染全站;确需全站生效的,改theme/app.scss并同步dark.scss。 - 表格卡片必须带
.full-table,否则height: 'auto'的 vxe-grid 撑不满,滚动条跑到 body 上。 - 查询卡不要写死控件宽度:
App.vue已用--next-search-control-width统一(含!important),页面覆盖不掉就改变量。 - 新组件的图标底色优先取
--next-accent-N,暗色模式只需在dark.scss覆盖这一组即可全站跟随。
小结
- 加载顺序固定:
element-plus→app→other→element→page→media→dark。 - 变量三层:
--el-*(组件库)、--next-*(项目)、--next-accent-N(强调色板)。 - 页面级类只有三个常用:
.card-header、.full-table、.detail-item。 - 改外观的顺序:属性 → 页面 scoped →
page.scss→app.scss变量;永远别写裸色值和!important。