鸿蒙5 字体层级规范:标题24px/正文18px/辅助文本14px 实现指南

暗雨OL
发布于 2025-6-27 21:43
浏览
0收藏

一、鸿蒙5字体层级系统概述
在鸿蒙OS(HarmonyOS)应用开发中,字体层级规范是实现一致、专业UI的关键要素。本文将详细解析鸿蒙推荐的字体层级系统,并提供完整代码实现。

核心字体层级规范:
层级 标准尺寸 使用场景 字重
​​标题​​ 24px 页面主标题、卡片标题 Medium (500)
​​正文​​ 18px 主要内容、段落文本 Regular (400)
​​辅助文本​​ 14px 说明文字、标注信息 Regular (400)
​​小字​​ 12px 时间戳、标签等 Light (300)
二、字体系统实现方案

  1. 全局字体定义
    // utils/FontSystem.ets
    export class FontSystem {
    // 字体层级常量
    static HEADLINE_XL: FontInfo = { size: 32, weight: 600 }; // 超大标题
    static HEADLINE: FontInfo = { size: 24, weight: 500 }; // 标准标题
    static HEADLINE_SM: FontInfo = { size: 20, weight: 500 }; // 小标题

static BODY_LG: FontInfo = { size: 20, weight: 400 }; // 大正文
static BODY: FontInfo = { size: 18, weight: 400 }; // 标准正文
static BODY_SM: FontInfo = { size: 16, weight: 400 }; // 小正文

static CAPTION: FontInfo = { size: 14, weight: 400 }; // 辅助文本
static CAPTION_SM: FontInfo = { size: 12, weight: 300 }; // 小辅助文本

// 应用字体到Text组件的方法
static applyFont(textComp: Text, fontInfo: FontInfo, color?: ResourceColor) {
textComp
.fontSize(fontInfo.size)
.fontWeight(fontInfo.weight);

if (color) {
  textComp.fontColor(color);
}

}

// 字体配置接口
interface FontInfo {
size: number;
weight: number;
}
}
2. 深色模式字体颜色规范
// models/FontColors.ets
export class FontColors {
// 浅色模式
static PRIMARY_LIGHT: ResourceColor = ‘#182431’; // 主要文字
static SECONDARY_LIGHT: ResourceColor = ‘#64748B’; // 次要文字
static ACCENT_LIGHT: ResourceColor = ‘#0F62FE’; // 强调文字
static DISABLED_LIGHT: ResourceColor = ‘#CBD5E1’; // 禁用状态

// 深色模式
static PRIMARY_DARK: ResourceColor = ‘#FFFFFF’; // 主要文字
static SECONDARY_DARK: ResourceColor = ‘#94A3B8’; // 次要文字
static ACCENT_DARK: ResourceColor = ‘#3182F6’; // 强调文字
static DISABLED_DARK: ResourceColor = ‘#475569’; // 禁用状态
}
三、标准化文本组件实现

  1. 标题组件
    // components/Typography/Headline.ets
    import { FontSystem } from ‘…/…/utils/FontSystem’;
    import { FontColors } from ‘…/…/models/FontColors’;

@Component
export struct Headline {
// 标题文本
private content: ResourceStr = ‘’;
// 文本颜色(默认主色)
@Prop color: ResourceColor = FontColors.PRIMARY_LIGHT;
// 层级(默认标准标题)
@Prop level: ‘xl’ | ‘normal’ | ‘sm’ = ‘normal’;
// 对齐方式
@Prop align: TextAlign = TextAlign.Start;
// 深色模式支持
@StorageProp(‘darkMode’) isDarkMode: boolean = false;

build() {
Text(this.content)
.let(FontSystem.applyFont,
this.getFontInfo(),
this.getActualColor())
.textAlign(this.align)
.maxLines(2)
.lineHeight(this.getLineHeight())
.textOverflow({ overflow: TextOverflow.Ellipsis })
}

// 获取实际字体配置
private getFontInfo(): FontSystem.FontInfo {
switch (this.level) {
case ‘xl’: return FontSystem.HEADLINE_XL;
case ‘sm’: return FontSystem.HEADLINE_SM;
default: return FontSystem.HEADLINE;
}
}

// 获取实际颜色
private getActualColor(): ResourceColor {
if (this.isDarkMode && this.color === FontColors.PRIMARY_LIGHT) {
return FontColors.PRIMARY_DARK;
}
return this.color;
}

// 获取合适行高
private getLineHeight(): Length {
const fontSize = this.getFontInfo().size;
return fontSize * 1.5;
}
}
2. 正文组件
// components/Typography/BodyText.ets
import { FontSystem } from ‘…/…/utils/FontSystem’;
import { FontColors } from ‘…/…/models/FontColors’;

@Component
export struct BodyText {
// 正文内容
private content: ResourceStr = ‘’;
// 层级(大/标准/小)
@Prop level: ‘lg’ | ‘normal’ | ‘sm’ = ‘normal’;
// 文本颜色
@Prop color: ResourceColor = FontColors.PRIMARY_LIGHT;
// 是否可选中
@Prop selectable: boolean = false;
// 深色模式支持
@StorageProp(‘darkMode’) isDarkMode: boolean = false;

build() {
Text(this.content)
.let(FontSystem.applyFont,
this.getFontInfo(),
this.getActualColor())
.textAlign(TextAlign.Start)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.maxLines(undefined) // 无行数限制
.selectable(this.selectable)
.lineHeight(this.getLineHeight())
}

private getFontInfo(): FontSystem.FontInfo {
switch (this.level) {
case ‘lg’: return FontSystem.BODY_LG;
case ‘sm’: return FontSystem.BODY_SM;
default: return FontSystem.BODY;
}
}

private getActualColor(): ResourceColor {
if (this.isDarkMode && this.color === FontColors.PRIMARY_LIGHT) {
return FontColors.PRIMARY_DARK;
}
return this.color;
}

private getLineHeight(): Length {
const fontSize = this.getFontInfo().size;
return fontSize * 1.6; // 正文行高比例更高
}
}
3. 辅助文本组件
// components/Typography/CaptionText.ets
import { FontSystem } from ‘…/…/utils/FontSystem’;
import { FontColors } from ‘…/…/models/FontColors’;

@Component
export struct CaptionText {
private content: ResourceStr = ‘’;
// 层级(标准/小)
@Prop level: ‘normal’ | ‘sm’ = ‘normal’;
// 文本颜色(默认次要文本)
@Prop color: ResourceColor = FontColors.SECONDARY_LIGHT;
// 图标资源
@Prop icon?: Resource = undefined;
// 深色模式支持
@StorageProp(‘darkMode’) isDarkMode: boolean = false;

build() {
Row() {
// 可选的图标
if (this.icon) {
Image(this.icon)
.width(this.getIconSize())
.height(this.getIconSize())
.margin({ right: 4 })
.objectFit(ImageFit.Contain)
}

  // 辅助文本
  Text(this.content)
    .fontSize(this.getFontSize())
    .fontWeight(this.getFontWeight())
    .fontColor(this.getActualColor())
    .opacity(0.8) // 辅助文本适当降低不透明度
}
.alignItems(VerticalAlign.Center)

}

private getFontSize(): number {
return this.level === ‘sm’ ?
FontSystem.CAPTION_SM.size :
FontSystem.CAPTION.size;
}

private getFontWeight(): number {
return this.level === ‘sm’ ?
FontSystem.CAPTION_SM.weight :
FontSystem.CAPTION.weight;
}

private getIconSize(): number {
return this.level === ‘sm’ ? 12 : 14;
}

private getActualColor(): ResourceColor {
// 深色模式自动调整
if (this.isDarkMode) {
if (this.color === FontColors.SECONDARY_LIGHT) {
return FontColors.SECONDARY_DARK;
}
if (this.color === FontColors.DISABLED_LIGHT) {
return FontColors.DISABLED_DARK;
}
}
return this.color;
}
}
四、完整页面实现示例

  1. 文章阅读页面
    // pages/ArticlePage.ets
    import { Headline } from ‘…/components/Typography/Headline’;
    import { BodyText } from ‘…/components/Typography/BodyText’;
    import { CaptionText } from ‘…/components/Typography/CaptionText’;
    import { FontColors } from ‘…/models/FontColors’;

@Entry
@Component
struct ArticlePage {
// 深色模式支持
@StorageProp(‘darkMode’) isDarkMode: boolean = false;

// 文章数据
private articleData = {
title: “鸿蒙OS 5字体系统深度解析”,
date: “2023年11月15日”,
author: “设计规范研究组”,
readTime: “8分钟阅读”,
content: `在鸿蒙OS 5设计系统中,字体层级规范对于创建一致性用户界面至关重要。规范推荐标题使用24px字重500,正文使用18px字重400,辅助文本使用14px字重400。

这种层级划分基于人眼视觉习惯和阅读舒适度科学原理。标题24px提供了足够的视觉权重,适合页面主要内容标识。正文18px被证明是长时间阅读最舒适的尺寸,既能保证清晰性又不会过度消耗视觉注意力。

辅助文本14px适用于图注、说明文字等次要信息,在保持可读性的同时降低视觉权重,形成清晰的信息层级。`
};

build() {
Column() {
// 标题区域
Headline({
content: this.articleData.title,
level: ‘xl’ // 超大标题
})
.margin({ top: 24, bottom: 16 })

  // 元信息区域
  Row() {
    CaptionText({
      content: this.articleData.date,
      color: FontColors.ACCENT_LIGHT
    })
    
    Divider()
      .height(12)
      .margin({ left: 8, right: 8 })
      .vertical(true)
      .strokeWidth(1)
    
    CaptionText({
      content: this.articleData.author
    })
    
    Divider()
      .height(12)
      .margin({ left: 8, right: 8 })
      .vertical(true)
      .strokeWidth(1)
    
    CaptionText({
      content: this.articleData.readTime,
      icon: $r('app.media.ic_clock') // 时钟图标
    })
  }
  .margin({ bottom: 32 })
  .padding(12)
  .borderRadius(8)
  .backgroundColor(this.isDarkMode ? '#2D3748' : '#F1F5F9')
  
  // 正文内容
  BodyText({
    content: this.articleData.content,
    level: 'normal',
    selectable: true // 允许选择文本
  })
  .margin({ bottom: 20 })
  
  // 副标题
  Headline({
    content: "关键设计原则",
    level: 'sm', // 小标题
    color: FontColors.ACCENT_LIGHT
  })
  .margin({ bottom: 16 })
  
  // 原则列表
  Column() {
    this.buildPrincipleItem("清晰层级", "使用三种基础字号形成明确视觉层级")
    this.buildPrincipleItem("阅读节奏", "正文18px配合1.6倍行高提供最佳阅读体验")
    this.buildPrincipleItem("空间平衡", "标题下方16px、正文段落后12px留白")
  }
}
.padding(24)
.backgroundColor(this.isDarkMode ? '#1A202C' : '#FFFFFF')

}

@Builder
buildPrincipleItem(title: string, description: string) {
Row() {
Column() {
// 序号
Headline({
content: ${this.getIndex() + 1},
color: FontColors.SECONDARY_LIGHT
})
}
.width(40)
.alignItems(HorizontalAlign.Center)

  // 内容
  Column() {
    BodyText({
      content: title,
      level: 'sm',
      color: FontColors.PRIMARY_LIGHT
    })
    .margin({ bottom: 4 })
    
    CaptionText({
      content: description
    })
  }
  .layoutWeight(1)
}
.padding(16)
.margin({ bottom: 12 })
.borderRadius(12)
.backgroundColor(this.isDarkMode ? '#2D3748' : '#F8FAFC')

}
}
2. 卡片信息展示
// components/InfoCard.ets
import { Headline } from ‘./Typography/Headline’;
import { BodyText } from ‘./Typography/BodyText’;
import { CaptionText } from ‘./Typography/CaptionText’;
import { FontColors } from ‘…/models/FontColors’;

@Component
export struct InfoCard {
private title: string = ‘卡片标题’;
private value: string = ‘核心数据’;
private description: string = ‘详细说明文本’;
@Prop icon: Resource = $r(‘app.media.ic_info’);

build() {
Column() {
// 标题与状态区域
Row() {
Headline({
content: this.title,
level: ‘sm’ // 小标题
})
.layoutWeight(1)

    // 状态标记
    CaptionText({
      content: "已更新",
      color: FontColors.ACCENT_LIGHT,
      level: 'sm'
    })
  }
  .margin({ bottom: 12 })
  
  Divider()
    .strokeWidth(1)
    .margin({ bottom: 16 })
    .color('#E2E8F0')
  
  // 主数值区域
  Row() {
    // 图标
    if (this.icon) {
      Image(this.icon)
        .width(24)
        .height(24)
        .margin({ right: 12 })
    }
    
    // 核心数值
    Headline({
      content: this.value,
      color: FontColors.ACCENT_LIGHT
    })
  }
  .margin({ bottom: 8 })
  
  // 说明文本
  BodyText({
    content: this.description,
    level: 'sm'
  })
  .margin({ bottom: 16 })
  
  // 辅助信息
  Row() {
    CaptionText({
      content: "最后更新: ",
      level: 'sm'
    })
    
    CaptionText({
      content: "2023-11-15",
      color: FontColors.ACCENT_LIGHT,
      level: 'sm'
    })
  }
}
.padding(20)
.borderRadius(16)
.shadow({ 
  radius: 8, 
  color: '#0000000D', 
  offsetY: 4 
})
.backgroundColor('#FFFFFF')
.width('100%')

}
}
五、响应式字体适配方案

  1. 设备尺寸敏感字体系统
    // utils/ResponsiveFontSystem.ets
    import deviceInfo from ‘@ohos.deviceInfo’;
    import display from ‘@ohos.display’;

export class ResponsiveFontSystem {
// 基础字体配置
static baseFontSize = {
headline: 24,
body: 18,
caption: 14
};

// 获取设备类型
private static getDeviceType() {
return deviceInfo.deviceType;
}

// 获取屏幕宽度
private static getScreenWidth() {
return display.getDefaultDisplay().width;
}

// 获取字体缩放比例
static getFontScale(): number {
const deviceType = this.getDeviceType();
const screenWidth = this.getScreenWidth();

// 平板和大屏设备使用更大的字体
if (deviceType === 'tablet' || screenWidth > 600) {
  return 1.1; // 放大10%
}

// 车机设备需要更大字体
if (deviceType === 'car') {
  return 1.3; // 放大30%
}

// 默认手机尺寸
return 1.0;

}

// 获取响应式字体大小
static fontSize(type: ‘headline’ | ‘body’ | ‘caption’): number {
const baseSize = this.baseFontSize[type];
const scale = this.getFontScale();

// 确保字体是2的倍数(Retina屏幕优化)
return Math.round(baseSize * scale);

}
}
2. 在组件中使用响应式字体
// components/Typography/ResponsiveBodyText.ets
import { ResponsiveFontSystem } from ‘…/…/utils/ResponsiveFontSystem’;

@Component
export struct ResponsiveBodyText {
private content: ResourceStr = ‘’;

build() {
Text(this.content)
.fontSize(ResponsiveFontSystem.fontSize(‘body’))
.fontWeight(FontWeight.Normal)
.fontColor(FontColors.PRIMARY_LIGHT)
.lineHeight(ResponsiveFontSystem.fontSize(‘body’) * 1.6)
}
}
六、字体对比度验证工具
// components/FontContrastChecker.ets
@Component
export struct FontContrastChecker {
@Prop bgColor: ResourceColor = ‘#FFFFFF’;
@Prop textColor: ResourceColor = ‘#000000’;

build() {
Column() {
Text(‘字体对比度测试’)
.fontSize(18)
.fontColor(this.textColor)
.margin(20)

  // 对比度信息
  Text(`对比度比例: ${this.calculateContrastRatio()}`)
    .fontSize(14)
    .fontColor(this.calculateContrastRatio() > 4.5 ? '#00C853' : '#FF3D00')
}
.padding(20)
.borderRadius(12)
.width('80%')
.backgroundColor(this.bgColor)

}

// 计算颜色对比度(WCAG 2.0标准)
private calculateContrastRatio(): number {
const luminance1 = this.getLuminance(this.bgColor);
const luminance2 = this.getLuminance(this.textColor);

const light = Math.max(luminance1, luminance2);
const dark = Math.min(luminance1, luminance2);

return (light + 0.05) / (dark + 0.05);

}

// 计算颜色亮度
private getLuminance(color: string): number {
// 将颜色转换为RGB
const hex = color.replace(‘#’, ‘’);
const r = parseInt(hex.substring(0, 2), 16) / 255;
const g = parseInt(hex.substring(2, 4), 16) / 255;
const b = parseInt(hex.substring(4, 6), 16) / 255;

// 计算相对亮度
const rSRGB = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
const gSRGB = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
const bSRGB = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);

return 0.2126 * rSRGB + 0.7152 * gSRGB + 0.0722 * bSRGB;

}
}
七、字体系统最佳实践

  1. 保持层级一致性
    // 正确做法:使用标准层级组件
    Headline({ content: “页面标题” })
    BodyText({ content: “主要说明文本” })
    CaptionText({ content: “补充信息” })

// 避免做法:手动设置字体
Text(“页面标题”)
.fontSize(24) // 直接硬编码尺寸
2. 合理使用留白规则
元素关系 间距规范
标题-正文 16px
正文-正文 8px
正文-辅助文本 12px
辅助文本-辅助文本 6px
3. 响应式断点设置
// 根据设备类型调整字体
fontSize: deviceType === ‘tablet’ ? 28 : 24
4. 深色模式适配方案
Text(“示例文本”)
.fontColor(this.isDarkMode ? FontColors.PRIMARY_DARK : FontColors.PRIMARY_LIGHT)
八、总结
鸿蒙OS 5的字体层级规范(标题24px/正文18px/辅助文本14px)是创建专业、一致用户体验的基础。通过本文介绍的实现方案,开发者可以:

创建标准化的文本组件系统
实现深色模式的自动适配
确保不同设备的响应式显示
满足WCAG标准的对比度要求
本文提供的组件代码可直接集成到鸿蒙应用项目中,帮助开发团队保持设计一致性,提升产品专业度。在实际开发中,建议结合设计系统文档进行微调,以满足具体产品需求。

分类
标签
收藏
回复
举报
回复
    相关推荐