18 KiB
18 KiB
Uni-App-X 样式规范 - CRMEB 风格指南
📚 概述
本文档定义了 mall 项目中所有页面的样式规范,参考 CRMEB 设计系统,使用 uni-app-x 的 .uvue 组件和 UTS 语言实现。
1. 颜色规范
1.1 基础色板
// 在 uni.scss 中定义,所有 .uvue 文件都可使用
// 主要色系
$primary-color: #1890ff // 蓝色 - 主交互色
$success-color: #52c41a // 绿色 - 成功状态
$warning-color: #faad14 // 黄色 - 警告状态
$error-color: #ff4d4f // 红色 - 错误状态
$info-color: #1890ff // 信息色
$disabled-color: #bfbfbf // 禁用色
// 文字色系
$text-primary: #000000 // 主文本(标题、重点内容)
$text-secondary: #666666 // 次文本(辅助信息)
$text-tertiary: #999999 // 三级文本(弱化信息)
$text-disabled: #bfbfbf // 禁用文本
// 背景色系
$background-primary: #ffffff // 主背景(卡片、模态框)
$background-secondary: #fafafa // 次背景
$background-tertiary: #f5f5f5 // 页面背景
// 边框色系
$border-color: #d9d9d9 // 默认边框色
$border-light: #f0f0f0 // 浅边框(弱化分割)
$border-dark: #bfbfbf // 深边框(强调分割)
1.2 使用示例
<template>
<view class="card">
<text class="title">主标题</text>
<text class="subtitle">副标题</text>
</view>
</template>
<style scoped lang="scss">
.card {
background: $background-primary;
border: 1px solid $border-color;
color: $text-primary;
}
.title {
color: $text-primary;
}
.subtitle {
color: $text-secondary;
}
</style>
2. 间距规范
2.1 间距系统
所有间距(margin、padding)必须使用 $space-* 变量,基准为 4px:
$space-0: 0 // 无间距
$space-xs: 4px // 极小 - 图标之间
$space-sm: 8px // 小 - 小组件间距
$space: 12px // 基础 - 标准间距
$space-md: 16px // 中 - 块级元素间距
$space-lg: 24px // 大 - 大块间距
$space-xl: 32px // 极大 - 页面级间距
$space-2xl: 48px // 双倍极大
2.2 间距使用规则
// ✅ 正确用法
// 单个方向
.button {
margin-bottom: $space; // 12px
padding: $space-md; // 16px
margin-right: $space-sm; // 8px
}
// 组合方向
.header {
padding: $space-lg $space-md; // 24px 16px
margin: $space 0; // 12px 0
}
// ❌ 错误用法 - 不要这样做!
.button {
margin-bottom: 12px; // 不要使用硬编码值
padding: 5px; // 不要使用任意值
margin-right: 15px; // 必须使用变量
}
2.3 常见间距场景
// 页面顶层间距
.page {
padding: $space-lg; // 24px - 页面内边距
}
// 卡片间距
.card {
padding: $space-md; // 16px
margin-bottom: $space-lg; // 24px
}
// 表单项目间距
.form-item {
margin-bottom: $form-item-margin-bottom; // 16px
}
// 列表项目间距
.list-item {
padding: $space-md;
border-bottom: 1px solid $border-light;
&:not(:last-child) {
margin-bottom: 0; // 用 border 替代
}
}
// 按钮组间距
.button-group {
display: flex;
gap: $space-sm; // 8px
}
// 文字间距
.paragraph {
line-height: $line-height-lg; // 1.8
margin-bottom: $space; // 12px
}
3. 圆角规范
3.1 圆角系统
$radius-0: 0 // 无圆角 - 锐角边缘
$radius-xs: 2px // 极小 - 微调
$radius-sm: 4px // 小 - 细微圆角
$radius: 6px // 默认 - 标准圆角(最常用)
$radius-lg: 8px // 大 - 明显圆角
$radius-xl: 12px // 极大 - 大圆角
$radius-2xl: 16px // 双倍极大
$radius-full: 9999px // 完全圆形(胶囊形)
3.2 圆角使用规则
// ✅ 正确用法
.card {
border-radius: $radius; // 6px - 卡片默认值
}
.badge {
border-radius: $radius-full; // 9999px - 圆形徽章
}
.button {
border-radius: $radius-sm; // 4px - 按钮圆角
}
.tag {
border-radius: $radius-sm; // 4px
}
.input {
border-radius: $radius-xs; // 2px - 输入框微调
}
// ❌ 不要这样做
.card {
border-radius: 8px; // 不要硬编码
border-radius: 50%; // 不要使用百分比
}
3.3 场景应用
// 页面卡片
.page-card {
background: $background-primary;
border-radius: $radius;
box-shadow: $shadow;
}
// 按钮
.btn {
border-radius: $radius-sm;
padding: $space-sm $space-md;
}
// 输入框
.input {
border-radius: $radius-xs;
border: 1px solid $border-color;
padding: $space-sm $space-sm;
}
// 头像(圆形)
.avatar {
border-radius: $radius-full;
width: 40px;
height: 40px;
}
// 标签
.tag {
display: inline-block;
padding: $space-xs $space-sm;
border-radius: $radius-sm;
background: $background-secondary;
}
4. 阴影规范
4.1 阴影系统
$shadow-none: none // 无阴影
$shadow-xs: 0 1px 2px 0 rgba(0,0,0, 0.05)
$shadow-sm: 0 1px 2px 0 rgba(0,0,0, 0.06)
$shadow: 0 4px 6px -1px rgba(0,0,0, 0.1), 0 2px 4px -1px rgba(0,0,0, 0.06) // 默认
$shadow-md: 0 10px 15px -3px rgba(0,0,0, 0.1), 0 4px 6px -2px rgba(0,0,0, 0.05)
$shadow-lg: 0 20px 25px -5px rgba(0,0,0, 0.1), 0 10px 10px -5px rgba(0,0,0, 0.04)
$shadow-xl: 0 25px 50px -12px rgba(0,0,0, 0.25) // 强调
4.2 阴影使用规则
// ✅ 正确用法
// 卡片 - 使用标准阴影
.card {
background: $background-primary;
border-radius: $radius;
box-shadow: $shadow; // 标准阴影
padding: $space-md;
}
// 浮动元素 - 使用较强阴影
.floating-btn {
box-shadow: $shadow-lg; // 强调阴影
}
// 模态框 - 使用最强阴影
.modal {
box-shadow: $shadow-xl;
}
// 弱化分割线
.divider {
box-shadow: $shadow-xs; // 极弱阴影
height: 1px;
}
// ❌ 不要这样做
.card {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); // 不要硬编码
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.3); // 不要使用任意值
}
4.3 场景应用
| 场景 | 阴影 | 说明 |
|---|---|---|
| 页面背景 | none | 无需阴影 |
| 卡片 | $shadow | 标准卡片 |
| 列表项 | $shadow-xs | 弱化分割 |
| 下拉菜单 | $shadow-lg | 浮动显示 |
| 模态框背景 | $shadow-xl | 强调焦点 |
| 悬停状态 | $shadow-md | 交互反馈 |
| 输入框 | $shadow-xs | 焦点提示 |
5. 字体规范
5.1 字体大小系统
$font-size-xs: 12px // 极小 - 说明文字
$font-size-sm: 13px // 小 - 辅助信息
$font-size: 14px // 默认 - 正文(最常用)
$font-size-md: 16px // 中 - 卡片标题
$font-size-lg: 18px // 大 - 页面二级标题
$font-size-xl: 20px // 极大 - 页面一级标题
$font-size-2xl: 24px // 双倍极大
$font-size-3xl: 30px // 三倍极大 - 页面主标题
5.2 行高和字重
// 行高
$line-height-xs: 1.2 // 紧凑 - 标题
$line-height-sm: 1.4 // 小
$line-height: 1.6 // 默认 - 正文
$line-height-lg: 1.8 // 大
$line-height-xl: 2 // 特大 - 宽松
// 字重
$font-weight-normal: 400 // 常规
$font-weight-medium: 500 // 中等(用于强调)
$font-weight-semibold: 600 // 半粗体(用于标题)
$font-weight-bold: 700 // 粗体(强调标题)
5.3 排版规范
// ✅ 正确用法
// 页面主标题
.page-title {
font-size: $font-size-lg;
font-weight: $font-weight-bold;
color: $text-primary;
margin-bottom: $space-md;
}
// 卡片标题
.card-title {
font-size: $font-size-md;
font-weight: $font-weight-semibold;
color: $text-primary;
}
// 正文
.content {
font-size: $font-size;
line-height: $line-height;
color: $text-secondary;
}
// 说明文字
.description {
font-size: $font-size-sm;
color: $text-tertiary;
line-height: $line-height-sm;
}
// ❌ 不要这样做
.title {
font-size: 18px; // 不要硬编码
font-weight: bold; // 不要使用 bold
line-height: 1.5; // 不要硬编码
}
5.4 排版场景
// 标题层级
h1 {
font-size: $font-size-3xl;
font-weight: $font-weight-bold;
}
h2 {
font-size: $font-size-xl;
font-weight: $font-weight-bold;
}
h3 {
font-size: $font-size-lg;
font-weight: $font-weight-semibold;
}
h4 {
font-size: $font-size-md;
font-weight: $font-weight-medium;
}
// 段落
p {
font-size: $font-size;
line-height: $line-height;
margin-bottom: $space-md;
}
// 列表项
li {
font-size: $font-size;
line-height: $line-height;
margin-bottom: $space-sm;
}
// 表格
td {
font-size: $font-size;
line-height: $line-height;
padding: $space-sm;
}
6. 动画和过渡
6.1 过渡系统
$transition-duration-fast: 0.1s
$transition-duration: 0.3s // 默认
$transition-duration-slow: 0.5s
$transition-timing-linear: linear // 匀速
$transition-timing: cubic-bezier(0.645, 0.045, 0.355, 1) // 标准缓动(推荐)
$transition-timing-ease-in: cubic-bezier(0.4, 0, 1, 1)
$transition-timing-ease-out: cubic-bezier(0, 0, 0.2, 1)
$transition-timing-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1)
6.2 过渡使用
// ✅ 正确用法
// 悬停效果
.button {
background: $primary-color;
transition: all $transition-duration $transition-timing;
&:active {
opacity: 0.8;
}
}
// 展开/折叠
.collapse {
transition: height $transition-duration $transition-timing;
}
// 淡入淡出
.fade-enter-active,
.fade-leave-active {
transition: opacity $transition-duration $transition-timing;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
7. 响应式设计
7.1 断点系统
$breakpoint-xs: 320px // 极小屏幕
$breakpoint-sm: 576px // 小屏(平板)
$breakpoint-md: 768px // 中屏(平板)
$breakpoint-lg: 992px // 大屏(笔记本)
$breakpoint-xl: 1200px // 特大屏(桌面)
$breakpoint-2xl: 1600px // 超大屏
7.2 媒体查询使用
// 手机优先设计
.page {
padding: $space; // 手机:12px
@media (min-width: $breakpoint-sm) {
padding: $space-md; // 平板:16px
}
@media (min-width: $breakpoint-lg) {
padding: $space-lg; // 桌面:24px
}
}
// 栅格布局
.grid {
display: grid;
grid-template-columns: 1fr; // 手机:1列
@media (min-width: $breakpoint-sm) {
grid-template-columns: repeat(2, 1fr); // 平板:2列
}
@media (min-width: $breakpoint-lg) {
grid-template-columns: repeat(3, 1fr); // 桌面:3列
}
}
8. Z-index 管理
8.1 Z-index 系统
$z-index-hide: -1
$z-index-base: 0
// 导航
$z-index-navbar: 100
$z-index-sidebar: 99
$z-index-sticky: 50
// 浮层
$z-index-dropdown: 1000
$z-index-popover: 1010
$z-index-tooltip: 1020
$z-index-modal-backdrop: 1040
$z-index-modal: 1050
$z-index-popconfirm: 1060
$z-index-notification: 1070
8.2 使用规则
.navbar {
z-index: $z-index-navbar; // 导航栏始终在最上
}
.modal-backdrop {
z-index: $z-index-modal-backdrop;
}
.modal {
z-index: $z-index-modal; // 模态框在背景上方
}
.tooltip {
z-index: $z-index-tooltip; // 提示框最高层
}
9. 常见组件样式
9.1 卡片(Card)
<template>
<view class="card">
<view class="card-header">
<text class="card-title">卡片标题</text>
</view>
<view class="card-body">
<!-- 内容 -->
</view>
<view class="card-footer">
<!-- 底部 -->
</view>
</view>
</template>
<style scoped lang="scss">
.card {
background: $background-primary;
border-radius: $radius;
box-shadow: $shadow;
overflow: hidden;
}
.card-header {
padding: $space-md;
border-bottom: 1px solid $border-light;
}
.card-title {
font-size: $font-size-md;
font-weight: $font-weight-semibold;
color: $text-primary;
}
.card-body {
padding: $space-md;
}
.card-footer {
padding: $space-md;
border-top: 1px solid $border-light;
display: flex;
gap: $space-sm;
justify-content: flex-end;
}
</style>
9.2 按钮(Button)
.btn {
height: $btn-height;
padding: 0 $space-md;
border: none;
border-radius: $radius-sm;
font-size: $font-size;
font-weight: $font-weight-medium;
cursor: pointer;
transition: all $transition-duration $transition-timing;
display: inline-flex;
align-items: center;
justify-content: center;
gap: $space-xs;
// 主按钮
&.btn-primary {
background: $primary-color;
color: #fff;
&:active {
opacity: 0.8;
}
}
// 次按钮
&.btn-default {
background: $background-secondary;
color: $text-primary;
border: 1px solid $border-color;
&:active {
background: $border-light;
}
}
// 危险按钮
&.btn-danger {
background: $error-color;
color: #fff;
&:active {
opacity: 0.8;
}
}
// 尺寸
&.btn-sm {
height: $btn-height-sm;
font-size: $font-size-sm;
padding: 0 $space-sm;
}
&.btn-lg {
height: $btn-height-lg;
font-size: $font-size-md;
padding: 0 $space-lg;
}
// 禁用状态
&:disabled,
&.disabled {
opacity: 0.6;
cursor: not-allowed;
}
}
9.3 输入框(Input)
.input {
height: $input-height;
padding: 0 $space-sm;
border: 1px solid $border-color;
border-radius: $radius-xs;
font-size: $font-size;
color: $text-primary;
background: $background-primary;
transition: border-color $transition-duration $transition-timing;
&::placeholder {
color: $text-tertiary;
}
&:focus {
outline: none;
border-color: $primary-color;
box-shadow: 0 0 0 3px rgba($primary-color, 0.1);
}
&:disabled {
background: $background-secondary;
color: $text-disabled;
cursor: not-allowed;
}
// 尺寸变体
&.input-sm {
height: $input-height-sm;
}
&.input-lg {
height: $input-height-lg;
}
}
10. 完整示例:列表页面
<template>
<view class="list-page">
<!-- 页面标题 -->
<view class="page-header">
<text class="page-title">数据列表</text>
<view class="page-actions">
<button class="btn btn-primary">新增</button>
<button class="btn btn-default">导出</button>
</view>
</view>
<!-- 搜索表单 -->
<view class="search-card">
<view class="form-item">
<text class="form-label">搜索:</text>
<input class="input" placeholder="请输入关键词" />
</view>
</view>
<!-- 列表内容 -->
<view class="list-card">
<view class="list-item" v-for="item in items" :key="item.id">
<view class="list-item-header">
<text class="list-item-title">{{ item.name }}</text>
<text class="list-item-status">{{ item.status }}</text>
</view>
<text class="list-item-desc">{{ item.description }}</text>
<view class="list-item-footer">
<text class="list-item-time">{{ item.createTime }}</text>
<view class="list-item-actions">
<button class="btn-link">编辑</button>
<button class="btn-link btn-danger">删除</button>
</view>
</view>
</view>
</view>
<!-- 分页 -->
<view class="pagination">
<button class="btn btn-sm">上一页</button>
<text>第 1 页,共 10 页</text>
<button class="btn btn-sm">下一页</button>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
const items = ref([
{ id: 1, name: '项目1', status: '进行中', description: '描述文本', createTime: '2024-01-01' },
{ id: 2, name: '项目2', status: '已完成', description: '描述文本', createTime: '2024-01-02' },
])
</script>
<style scoped lang="scss">
.list-page {
padding: $space-lg;
background: $background-tertiary;
}
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: $space-lg;
}
.page-title {
font-size: $font-size-lg;
font-weight: $font-weight-bold;
color: $text-primary;
}
.page-actions {
display: flex;
gap: $space-sm;
}
.search-card {
background: $background-primary;
border-radius: $radius;
padding: $space-md;
margin-bottom: $space-lg;
box-shadow: $shadow;
}
.form-item {
display: flex;
align-items: center;
gap: $space-md;
}
.form-label {
color: $text-secondary;
font-size: $font-size-sm;
}
.input {
height: $input-height;
padding: 0 $space-sm;
border: 1px solid $border-color;
border-radius: $radius-xs;
flex: 1;
}
.list-card {
background: $background-primary;
border-radius: $radius;
overflow: hidden;
box-shadow: $shadow;
margin-bottom: $space-lg;
}
.list-item {
padding: $space-md;
border-bottom: 1px solid $border-light;
&:last-child {
border-bottom: none;
}
}
.list-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: $space-sm;
}
.list-item-title {
font-size: $font-size-md;
font-weight: $font-weight-medium;
color: $text-primary;
}
.list-item-status {
font-size: $font-size-xs;
background: $background-secondary;
color: $text-secondary;
padding: $space-xs $space-sm;
border-radius: $radius-xs;
}
.list-item-desc {
font-size: $font-size-sm;
color: $text-secondary;
margin-bottom: $space-sm;
}
.list-item-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.list-item-time {
font-size: $font-size-xs;
color: $text-tertiary;
}
.list-item-actions {
display: flex;
gap: $space-sm;
}
.btn-link {
background: none;
border: none;
color: $primary-color;
padding: 0;
font-size: $font-size-sm;
cursor: pointer;
&.btn-danger {
color: $error-color;
}
}
.pagination {
display: flex;
justify-content: center;
align-items: center;
gap: $space-md;
padding: $space-lg 0;
}
</style>
总结
✅ 必须遵循的规范:
- 所有色值必须使用
$color-*变量 - 所有间距必须使用
$space-*变量 - 所有圆角必须使用
$radius-*变量 - 所有阴影必须使用
$shadow-*变量 - 所有字体大小必须使用
$font-size-*变量 - 所有过渡必须使用
$transition-*变量
❌ 禁止:
- 硬编码任何数值(色值、尺寸、间距等)
- 使用不规范的命名
- 创建局部样式变量与系统冲突
📝 维护建议:
- 定期审查样式规范的使用情况
- 在新增样式变量前,检查是否已有相近的
- 保持设计系统的一致性和可维护性
文档版本: 1.0
最后更新: 2026-01-31
维护者: AI Assistant