鸿蒙实战:字体令牌系统——AppFonts 与排版规范

鸿蒙实战:字体令牌系统------AppFonts 与排版规范

前言(必读)

图:鸿蒙实战:字体令牌系统------AppFonts 与排版规范(第 68 篇) 运行效果截图(HarmonyOS NEXT)

一致的排版系统是设计质量的标志。鸿蒙应用开发中,字号 fp、圆角 radius、间距 padding、阴影 shadow 这四个维度如果有各自独立的散落定义,页面之间会出现肉眼可见的不协调。本文将详细讲解本项目的四维一体的排版令牌系统

图:AppFonts 四维令牌体系------字号/圆角/间距/阴影的统一管理结构
#mermaid-svg-XUL2hjRJfIEFoER7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XUL2hjRJfIEFoER7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XUL2hjRJfIEFoER7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XUL2hjRJfIEFoER7 .error-icon{fill:#552222;}#mermaid-svg-XUL2hjRJfIEFoER7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XUL2hjRJfIEFoER7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XUL2hjRJfIEFoER7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XUL2hjRJfIEFoER7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XUL2hjRJfIEFoER7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XUL2hjRJfIEFoER7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XUL2hjRJfIEFoER7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XUL2hjRJfIEFoER7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XUL2hjRJfIEFoER7 .marker.cross{stroke:#333333;}#mermaid-svg-XUL2hjRJfIEFoER7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XUL2hjRJfIEFoER7 p{margin:0;}#mermaid-svg-XUL2hjRJfIEFoER7 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XUL2hjRJfIEFoER7 .cluster-label text{fill:#333;}#mermaid-svg-XUL2hjRJfIEFoER7 .cluster-label span{color:#333;}#mermaid-svg-XUL2hjRJfIEFoER7 .cluster-label span p{background-color:transparent;}#mermaid-svg-XUL2hjRJfIEFoER7 .label text,#mermaid-svg-XUL2hjRJfIEFoER7 span{fill:#333;color:#333;}#mermaid-svg-XUL2hjRJfIEFoER7 .node rect,#mermaid-svg-XUL2hjRJfIEFoER7 .node circle,#mermaid-svg-XUL2hjRJfIEFoER7 .node ellipse,#mermaid-svg-XUL2hjRJfIEFoER7 .node polygon,#mermaid-svg-XUL2hjRJfIEFoER7 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XUL2hjRJfIEFoER7 .rough-node .label text,#mermaid-svg-XUL2hjRJfIEFoER7 .node .label text,#mermaid-svg-XUL2hjRJfIEFoER7 .image-shape .label,#mermaid-svg-XUL2hjRJfIEFoER7 .icon-shape .label{text-anchor:middle;}#mermaid-svg-XUL2hjRJfIEFoER7 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XUL2hjRJfIEFoER7 .rough-node .label,#mermaid-svg-XUL2hjRJfIEFoER7 .node .label,#mermaid-svg-XUL2hjRJfIEFoER7 .image-shape .label,#mermaid-svg-XUL2hjRJfIEFoER7 .icon-shape .label{text-align:center;}#mermaid-svg-XUL2hjRJfIEFoER7 .node.clickable{cursor:pointer;}#mermaid-svg-XUL2hjRJfIEFoER7 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XUL2hjRJfIEFoER7 .arrowheadPath{fill:#333333;}#mermaid-svg-XUL2hjRJfIEFoER7 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XUL2hjRJfIEFoER7 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XUL2hjRJfIEFoER7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XUL2hjRJfIEFoER7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XUL2hjRJfIEFoER7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XUL2hjRJfIEFoER7 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XUL2hjRJfIEFoER7 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XUL2hjRJfIEFoER7 .cluster text{fill:#333;}#mermaid-svg-XUL2hjRJfIEFoER7 .cluster span{color:#333;}#mermaid-svg-XUL2hjRJfIEFoER7 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XUL2hjRJfIEFoER7 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XUL2hjRJfIEFoER7 rect.text{fill:none;stroke-width:0;}#mermaid-svg-XUL2hjRJfIEFoER7 .icon-shape,#mermaid-svg-XUL2hjRJfIEFoER7 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XUL2hjRJfIEFoER7 .icon-shape p,#mermaid-svg-XUL2hjRJfIEFoER7 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XUL2hjRJfIEFoER7 .icon-shape .label rect,#mermaid-svg-XUL2hjRJfIEFoER7 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XUL2hjRJfIEFoER7 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XUL2hjRJfIEFoER7 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XUL2hjRJfIEFoER7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} AppFonts 排版系统
字号 size
圆角 radius
间距 spacing
AppShadow 阴影系统
阴影层级
xs: 10fp
sm: 12fp
md: 14fp
lg: 16fp
xl: 20fp
xxl: 28fp
sm: 8vp
md: 12vp
lg: 20vp
full: 999vp
xs: 4vp
sm: 8vp
md: 16vp
lg: 24vp


一、四维令牌全景

本项目的排版系统由四个令牌类组成,定义在同一个文件中:

typescript 复制代码
// 文件:common/theme/AppFonts.ets
//
// 维度          类名           管理内容
// ─────────────────────────────────────
// 字体          AppFonts      字号阶梯 + 字重 + 字体族
// 圆角          AppRadius     6 级圆角系统
// 间距          AppSpacing    7 级间距系统
// 阴影          AppShadow     7 级阴影系统

二、AppFonts:字号阶梯

2.1 完整定义

typescript 复制代码
export class AppFonts {
  // 字体族
  static readonly SANS: string = 'HarmonyOS Sans SC, HarmonyOS Sans'
  static readonly SERIF: string = 'HarmonyOS Sans SC, Source Han Serif CN'

  // 字号阶梯(fp · 跟随系统字号缩放)
  static readonly DISPLAY: number = 32   // 大标题
  static readonly TITLE_L: number = 28   // HarmonyOS 大标题栏
  static readonly TITLE: number = 22     // 页面标题
  static readonly SUBTITLE: number = 18  // 子标题
  static readonly BODY_L: number = 16    // 正文大
  static readonly BODY: number = 14      // 正文
  static readonly CAPTION: number = 12   // 辅助文
  static readonly TINY: number = 10      // 标签

  // 字重
  static readonly W_REGULAR: FontWeight = FontWeight.Regular
  static readonly W_MEDIUM: FontWeight = FontWeight.Medium
  static readonly W_BOLD: FontWeight = FontWeight.Bold
}

2.2 字号阶梯对照

复制代码
32 fp ─ DISPLAY     首页品牌名「鹿鹿·笔迹心理」
28 fp ─ TITLE_L     HarmonyOS 大标题栏标题
22 fp ─ TITLE       页面标题「笔迹分析报告」
18 fp ─ SUBTITLE    卡片子标题、雷达图数字
16 fp ─ BODY_L      段落正文(分享文案)
14 fp ─ BODY        常规正文
12 fp ─ CAPTION     辅助说明、标签、时间戳
10 fp ─ TINY        元数据标签、版权信息

2.3 字体族策略

typescript 复制代码
// 无衬线体(正文/按钮)
static readonly SANS: string = 'HarmonyOS Sans SC, HarmonyOS Sans'
// 1. 优先 HarmonyOS Sans SC(中文字体)
// 2. 降级 HarmonyOS Sans(英文字体)

// 衬线体(品牌/标题/引用)
static readonly SERIF: string = 'HarmonyOS Sans SC, Source Han Serif CN'
// 1. 优先 HarmonyOS Sans SC(HarmonyOS 系统字体)
// 2. 降级 Source Han Serif CN(思源宋体)

选择思源宋体作为降级字体而非默认的衬线体,是因为本项目的定位是「手写 + 治愈风」,思源宋体的笔触比标准衬线体更具温度感。


三、AppRadius:圆角系统

3.1 完整定义

typescript 复制代码
export class AppRadius {
  static readonly XS: number = 6    // 最小圆角
  static readonly S: number = 10    // 小卡片/头像
  static readonly M: number = 14    // 按钮/普通卡片
  static readonly L: number = 20    // 大卡片/容器
  static readonly XL: number = 24   // 特圆卡片
  static readonly ROUND: number = 999  // 胶囊按钮(完全圆角)
}

3.2 圆角应用场景

复制代码
ROUND → [ 分享 ] 胶囊按钮       border-radius: 999px
  XL  → ┌──────────────┐       特圆卡片(TapSharePage 分享卡片)
        │              │
   L   → ┌──────────┐          大容器卡片(标签式 AI 摘要框)
         │           │
   M   → [ 拍照 ]    默认按钮   常规按钮
   S   → (头像)      小卡片     小卡片/标签
   XS  → ┌──────────┐          最小圆角(强调框)
         │           │

3.3 圆角设计原则

复制代码
递增阶梯:6 → 10 → 14 → 20 → 24 → 999
          XS    S    M    L    XL   ROUND

原则:每次增加约 40-60%,肉眼可分辨。
确保相邻层级差异 ≥ 4px,避免视觉模糊。

四、AppSpacing:间距系统

4.1 完整定义

typescript 复制代码
export class AppSpacing {
  static readonly XXS: number = 4    // 极紧凑(图标与文字的间隙)
  static readonly XS: number = 8     // 紧凑(标题与副标题的间距)
  static readonly S: number = 12     // 稍紧凑(标签之间的间距)
  static readonly M: number = 16     // 常规(卡片内 padding)
  static readonly L: number = 20     // 稍宽松(页面左右边距)
  static readonly XL: number = 28    // 宽松(模块间距)
  static readonly XXL: number = 36   // 极宽松(大模块间距)
}

4.2 7 级间距使用规范

复制代码
 距离    层级       使用位置                 示例
────────────────────────────────────────────────
  4px    XXS   文字与图标间隙      title + subtitle
  8px    XS    标题与副标题       HmTitleBar top/bottom
 12px    S     标签/按钮间距      情绪标签 gap
 16px    M     卡片内边距         padding: 16px
 20px    L     页面左右边距       padding(left/right: 20)
 28px    XL    大模块间距         首页欢迎区与 Hero 的 gap
 36px    XXL   最大间距           页面底部留白

4.3 调用示例

typescript 复制代码
// 页面左右边距统一 20px
Column()
  .padding({ left: AppSpacing.L, right: AppSpacing.L })

// 标题与副标题间距 8px
Text('标题').fontSize(AppFonts.TITLE)
Text('副标题')
  .margin({ top: AppSpacing.XXS })

// 情绪标签间距 12px
Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Center }) {
  ForEach(this.tags, (tag: string) => {
    Text(tag).margin({ right: AppSpacing.S, bottom: AppSpacing.S })
  })
}

// 模块间距 28px
Scroll() {
  Column({ space: AppSpacing.XL }) {
    WelcomeSection()
    HeroSection()
    RecentReports()
    InspireSection()
  }
}

五、跨页面排版一致性

5.1 全应用统一 padding

所有页面的左右边距 都使用 AppSpacing.L = 20,这是 HarmonyOS Design 推荐的页面标准边距(safe area margin)。

typescript 复制代码
// MetaServiceCard.ets
Column()
  .padding({ left: AppSpacing.L, right: AppSpacing.L })

// CapturePage.ets
Column()
  .padding({ left: AppSpacing.L, right: AppSpacing.L })

// ReportDetailPage.ets
Column()
  .padding({ left: AppSpacing.L, right: AppSpacing.L })

5.2 卡片统一背景色

typescript 复制代码
// 所有卡片背景统一为 CARD = #FFFCF7
Column()
  .backgroundColor(AppColors.CARD)
  .borderRadius(AppRadius.XL)       // 特圆
  // 或
  .borderRadius(AppRadius.L)        // 大圆角

5.3 排版一致性对比

复制代码
❌ 无令牌系统时:
  Page A: padding 16, fontSize 16, borderRadius 12
  Page B: padding 24, fontSize 15, borderRadius 10
  → 肉眼可见的不一致

✅ 有令牌系统时:
  Page A: padding AppSpacing.L, fontSize AppFonts.BODY, borderRadius AppRadius.M
  Page B: padding AppSpacing.L, fontSize AppFonts.BODY, borderRadius AppRadius.M
  → 完美一致

六、与 HarmonyOS Design 的一致性

HarmonyOS 规范 本项目令牌
大标题字号 AppFonts.TITLE_L 28fp
正文字号 AppFonts.BODY 14fp
辅助文字 AppFonts.CAPTION 12fp
页面边距 AppSpacing.L 20px
安全区横向 AppSpacing.L 20px
标题字重 AppFonts.W_MEDIUM Medium
正文字重 AppFonts.W_REGULAR Regular

七、工程管理

规格表

令牌类 管理数量 文件行数
AppFonts 10(字号 8 + 字重 3) 24 行
AppRadius 6 7 行
AppSpacing 7 8 行
AppShadow 7 30 行

全部四个类加起来不到 80 行代码,却管理了整个应用的所有排版变量。

调用频次

typescript 复制代码
// 项目中部分引用统计(基于 Grep 估算)
AppFonts.BODY     → 35+ 次引用    最高频
AppSpacing.L      → 20+ 次引用    二级高频
AppRadius.XL      → 12+ 次引用
AppShadow.CARD    → 8+ 次引用

扩展建议

typescript 复制代码
// 如果需要支持动态字号(系统字体缩放)
// 当前 fp 会跟随系统设置自动缩放,无需额外代码

// 如果需要支持多语言(如英文版)
// 英文环境下建议替换字体族为:
static readonly SANS_EN: string = 'SF Pro Text, Helvetica Neue'

八、注意事项与常见问题

8.1 开发注意事项

在正式开发前,建议按以下步骤完成环境准备与前置检查:

  1. 版本确认:检查 DevEco Studio 与 SDK 版本,确保满足目标 API Level 要求
  2. 权限声明 :在 module.json5requestPermissions 字段中提前声明所有需要的系统权限
  3. 设备能力检查:调用前验证设备是否支持目标能力(相机、NFC、传感器等)
  4. 异步封装 :所有耗时操作(数据库、文件 I/O、网络请求)统一使用 async/await 处理
  5. 资源释放 :在组件 aboutToDisappear() 生命周期钩子中及时释放系统资源,防止内存泄漏

8.2 常见错误与解决方案

常见问题快速排查表:

问题类型 排查方向 参考方法
应用崩溃 查看 hilog 错误日志 hilog.error(TAG, "...", e.message)
状态丢失 检查 AppStorage 键名拼写 统一使用常量管理键名
动画不流畅 避免在 animateTo 回调中执行 I/O 动画与数据操作分离

总结

  • 四维令牌系统:AppFonts / AppRadius / AppSpacing / AppShadow 统一管理
  • 8 级字号阶梯:从 10fp 到 32fp,覆盖全场景
  • 6 级圆角系统:XS → ROUND 递增体系
  • 7 级间距系统:4px → 36px 覆盖所有间距需求
  • 字体族策略:HarmonyOS Sans SC 优先 + 思源宋体降级
  • 跨页面一致性:所有页面统一 padding / borderRadius / fontSize
  • HarmonyOS Design 兼容:大标题 28fp、边距 20px 等符合规范

下一篇将讲解线性渐变与梯度色彩应用,看 HomePage 的 Hero CTA 渐变和情绪渐变条的实现。


📌 收藏提示:排版令牌是设计系统的骨架,项目初期就建立它能避免 80% 的排版不一致问题。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:


七、排版令牌应用进阶

7.1 响应式字号策略

鸿蒙支持通过 fp 单位自动适配用户的系统字号偏好设置,令牌中所有字号均已使用 fp

typescript 复制代码
// ✅ 使用 fp,响应系统字号偏好
Text('标题').fontSize(AppFonts.sizeXl)  // 20fp

// ❌ 使用 vp,不响应系统字号偏好
Text('标题').fontSize(20)               // 20vp,固定不变

7.2 间距令牌的网格系统

间距令牌基于 4dp 网格,所有值均为 4 的倍数:

令牌 用途场景
spacingXs 4vp 图标与文字内间距
spacingSm 8vp 组件内部间距
spacingMd 16vp 卡片内边距
spacingLg 24vp 页面边距
spacingXl 32vp 页面区块间距

7.3 圆角令牌与品牌感知

圆角大小影响品牌形象:

  • 直角(0vp):专业、严肃、科技感
  • 小圆角(8vp):友好、现代、克制
  • 大圆角(20vp):温暖、活泼、治愈感
  • 全圆(999vp):按钮/标签的「药丸」形态

本项目采用中等偏大的圆角,契合「米色治愈风」的品牌定位。

7.4 令牌命名的一致性约定

四维令牌的命名遵循统一前缀规则,便于 IDE 自动补全:

维度 前缀 示例
字号 size sizeXs / sizeSm / sizeMd / sizeLg / sizeXl
圆角 radius radiusSm / radiusMd / radiusLg / radiusFull
间距 spacing spacingXs / spacingSm / spacingMd / spacingLg
行高 lineHeight lineHeightSm / lineHeightMd / lineHeightLg

输入 AppFonts. 后 IDE 会列出所有令牌,极大提高开发效率。

7.5 令牌系统的扩展路径

随着项目规模增大,四维令牌可进一步扩展:

  • 字重令牌fontWeightLight / fontWeightRegular / fontWeightMedium / fontWeightBold
  • 字族令牌fontFamilyDefault / fontFamilyMono(支持自定义字体包)
  • 动态缩放比:基于屏幕密度(density)自动计算最终渲染尺寸

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!

相关推荐
xd1855785551 小时前
药箱顾问-药品说明书解读的HarmonyOS开发实践
人工智能·华为·harmonyos·鸿蒙
在书中成长1 小时前
HarmonyOS 小游戏《对战五子棋》开发第34篇 - ArkTS中复用UI的方法
ui·harmonyos
木木子221 小时前
# [特殊字符] 健身模拟器 — 鸿蒙ArkTS完整技术解析
华为·harmonyos
爸爸6192 小时前
鸿蒙实战:@State 本地状态与 UI 刷新
ui·华为·harmonyos·鸿蒙系统
念雨思2 小时前
每日穿搭助手:鸿蒙AI应用开发实战——AI衣橱,每日穿搭不再愁
人工智能·华为·powerpoint·harmonyos·鸿蒙
l134062082352 小时前
鸿蒙实战:从 rawfile 加载 AI 模型资源
人工智能·华为·harmonyos
心中有国也有家2 小时前
AtomGit Flutter 鸿蒙客户端:Flutter 鸿蒙应用的错误处理与优雅降级策略
学习·flutter·华为·harmonyos
xianjixiance_2 小时前
鸿蒙实战:UnclassifiedArchivePage 长按多选与批量归档
华为·harmonyos·鸿蒙系统
不才难以繁此生3 小时前
ArkUI 筛选状态实战:中式美食列表页怎么让关键词、分类和排序不互相打架
harmonyos·arkts·状态管理·arkui·中式美食