
鸿蒙5 字体层级规范:标题24px/正文18px/辅助文本14px 实现指南
一、鸿蒙5字体层级系统概述
在鸿蒙OS(HarmonyOS)应用开发中,字体层级规范是实现一致、专业UI的关键要素。本文将详细解析鸿蒙推荐的字体层级系统,并提供完整代码实现。
核心字体层级规范:
层级 标准尺寸 使用场景 字重
标题 24px 页面主标题、卡片标题 Medium (500)
正文 18px 主要内容、段落文本 Regular (400)
辅助文本 14px 说明文字、标注信息 Regular (400)
小字 12px 时间戳、标签等 Light (300)
二、字体系统实现方案
- 全局字体定义
// 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’; // 禁用状态
}
三、标准化文本组件实现
- 标题组件
// 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;
}
}
四、完整页面实现示例
- 文章阅读页面
// 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%')
}
}
五、响应式字体适配方案
- 设备尺寸敏感字体系统
// 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;
}
}
七、字体系统最佳实践
- 保持层级一致性
// 正确做法:使用标准层级组件
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标准的对比度要求
本文提供的组件代码可直接集成到鸿蒙应用项目中,帮助开发团队保持设计一致性,提升产品专业度。在实际开发中,建议结合设计系统文档进行微调,以满足具体产品需求。
