Files
2026-07-30 22:35:51 +08:00

5.5 KiB

OpenCloud 样式体系

这套体系用于让视觉规则集中、Vue 模板可读,同时保留 Tailwind 对一次性布局的灵活性。它不是“所有样式都写成全局类”,而是把会跨页面复用、带有产品语义或必须一致的规则集中管理。

分层

层级 文件 职责
设计令牌 src/styles/tokens.css 颜色、字体、渐变、阴影、动效时长等稳定决策
基础规则 src/styles/base.css 页面基线、选中文本、全局圆角策略
组件规则 src/styles/components.css 页面 Hero、容器、表单、面板、按钮等共享语义类
第三方主题 src/lib/theme.ts Naive UI 的全局主题契约;值应与设计令牌保持一致
单组件样式 Vue 文件的 <style scoped> 只属于一个功能的滑杆、动画、地图或媒体细节
一次性布局 Vue 模板中的 Tailwind 类 flex/grid、间距、响应式排列及确实只出现一次的视觉调整

src/style.css 只负责按以上顺序装配全局样式,不再直接堆放组件规则。

清新绿色策略

OpenCloud 的绿色应接近清晨的桉叶与嫩叶,而不是灰暗的苔藓色或高饱和的荧光青绿。

  • 品牌、导航与账户交互使用清透但稳重的桉叶绿。
  • 成功、通过和公开状态使用更偏嫩叶的成功绿色,与品牌色保持区分。
  • teal-* 和 emerald-* 是现有模板的兼容类名,实际色值由 tokens.css 重映射;不要假定它们仍是 Tailwind 默认色。
  • 不直接使用 Tailwind 默认 green-*、lime-*,也不要在组件里写亮绿色十六进制值或 RGB。
  • 新增绿色前先判断它属于品牌交互还是成功状态,并优先使用已有语义类或设计令牌。
语义 主色 深色 浅色表面
品牌/交互 #34745d #274c40 #f2faf6
成功/通过 #4d7f3b #35522c #f4faef

命名规则

  • 所有共享类使用 oc- 前缀,避免与 Naive UI、AMap 和 Tailwind 冲突。
  • 组件使用 .oc-block,内部结构使用 .oc-block__element,变体使用 .oc-block--modifier。
  • 变体不能脱离基础类使用,例如 oc-panel-button oc-panel-button--sky。
  • 类名描述用途,不描述当前颜色。例如使用 oc-field-error,而不是 oc-red-text。
  • 只有至少跨两个页面复用,或承载全局产品规则时才新增共享类。仅服务单一功能的代码留在组件内。

常用契约

页面结构

<section class="oc-page-hero">
  <div class="oc-container oc-container--content oc-page-hero__inner">
    <p class="oc-page-eyebrow">Cloud Upload</p>
    <h1 class="oc-page-title">上传云图</h1>
    <p class="oc-page-description">页面描述</p>
  </div>
</section>

<main class="oc-container oc-container--content oc-page-content">
  <!-- 页面内容 -->
</main>

容器宽度只有三个语义档位:oc-container--narrow、oc-container--content、oc-container--wide。不要在同类页面重复手写 max-w-* mx-auto px-*。

Hero 同时包含左侧介绍和右侧状态卡时,使用 oc-page-hero__split。它会在有效视口达到 900px 时启用接近均衡的双栏,避免浏览器缩放到 125% 后过早堆叠;需要两栏等高时同时添加 oc-page-hero__split--stretch。

表单

<label class="oc-field-label">
  拍摄时间 <span class="oc-field-required">*</span>
</label>
<input class="oc-field-control" />
<p class="oc-field-help">补充说明</p>
<p class="oc-field-error">错误信息</p>

原生 input、select 和 textarea 共用 oc-field-control。尺寸或布局差异可以追加少量 Tailwind 类,例如 class="oc-field-control mt-2 resize-none"。

信息与面板

  • oc-section-label:详情面板中的字段标题。
  • oc-stat-label / oc-stat-value:统计数据的标签和值。
  • oc-inset-panel:详情中的浅色信息块。
  • oc-panel-card / oc-panel-card-soft / oc-panel-card-xl:普通、柔和和大型卡片的硬阴影。
  • oc-floating-panel / oc-modal-shell:浮动菜单与普通方形弹窗的共享表面。
  • oc-surface:普通 HTML 容器的标准白色表面。
  • oc-empty-card:空状态表面。

按钮

Naive UI 按钮继续使用 type="default",视觉语义由共享类控制:

<NButton class="oc-panel-button oc-panel-button--neutral" type="default">
  取消
</NButton>
<NButton class="oc-panel-button oc-panel-button--sky" type="default">
  保存
</NButton>

页面级主操作使用 oc-primary-button;面板内操作使用 oc-panel-button。可用变体为 neutral、sky、teal、amber、danger,不要临时创建新的强调色。其中 teal 是兼容命名,视觉上使用的是清新桉叶绿。

新增或修改样式的决策顺序

  1. 先确认现有 oc-* 类能否表达该语义。
  2. 一次性布局使用 Tailwind,不为单次 flex、gap 或响应式网格创建共享类。
  3. 跨页面重复或属于产品视觉契约时,在 components.css 增加语义类;涉及稳定视觉值时先在 tokens.css 增加令牌。
  4. 只属于一个交互或组件的规则放在对应 Vue 文件的 <style scoped> 中。
  5. 修改 Naive UI 全局值时同步检查 theme.ts 与 tokens.css。

验证

提交前运行:

npm run check:styles
npm run build

check:styles 会阻止已经淘汰的重复 class、非项目调色板以及缺少基础类的按钮修饰类回流;build 同时执行 Vue/TypeScript 类型检查和生产构建。