uniapp实现的H5字体跨平台优化-如何兼容小软件


前言

1. 添加条件编译

文件: src/style/fonts.scss

使用 /* #ifndef MP *//* #endif */ 包裹 @font-face 定义,确保:

  • H5 和 App 平台正常加载字体文件
  • 小程序平台不会引入无效的 @font-face 代码
/* #ifndef MP */
// H5 和 App 平台使用 @font-face
@font-face {
font-family: 'PingFang SC';
src: url('/static/fonts/PingFangRegular.ttf') format('truetype');
font-weight: 400;
}
/* #endif */
/* #ifdef MP */
// 小程序平台说明注释
/* #endif */

2. 完善字体栈

文件: src/App.vue

设置了完整的字体降级方案:

font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont,
             'Helvetica Neue', Arial, 'Microsoft YaHei', sans-serif;

3. 添加平台说明注释

在关键文件中添加了详细的平台兼容性说明:

  • src/style/fonts.scss - 字体定义文件
  • src/App.vue - 全局样式
  • src/uni.scss - SCSS 变量

4. 创建小程序字体加载工具

文件: src/utils/loadMiniProgramFonts.js

/**
* 小程序自定义字体加载工具
*
* 使用说明:
* 1. 将字体文件上传到 CDN(支持 HTTPS)
* 2. 在小程序后台配置 CDN 域名白名单
* 3. 在 App.vue 的 onLaunch 中调用此函数
*
* 注意事项:
* - 字体文件必须是网络地址(不能是本地文件)
* - 字体文件大小建议 < 2MB
* - 加载字体会增加首屏加载时间
* - 建议只在必要时使用(如品牌字体要求)
*/
/**
* 加载微信小程序字体
* @param {Object} options 配置选项
* @param {string} options.fontFamily 字体名称,默认 'PingFang SC'
* @param {string} options.fontUrl 字体文件 CDN 地址
* @param {Function} options.onSuccess 成功回调
* @param {Function} options.onFail 失败回调
*/
export function loadWechatFont(options = {}) {
// #ifdef MP-WEIXIN
const {
fontFamily = 'PingFang SC',
fontUrl = '',
onSuccess = () => {},
onFail = () => {}
} = options
if (!fontUrl) {
console.warn('[字体加载] 未提供字体 URL')
return
}
console.log(`[字体加载] 开始加载字体: ${fontFamily}`)
wx.loadFontFace({
family: fontFamily,
source: `url("${fontUrl}")`,
success: (res) => {
console.log(`[字体加载] 字体加载成功: ${fontFamily}`, res)
onSuccess(res)
},
fail: (err) => {
console.error(`[字体加载] 字体加载失败: ${fontFamily}`, err)
onFail(err)
}
})
// #endif
}
/**
* 加载支付宝小程序字体
* @param {Object} options 配置选项
*/
export function loadAlipayFont(options = {}) {
// #ifdef MP-ALIPAY
const {
fontFamily = 'PingFang SC',
fontUrl = '',
onSuccess = () => {},
onFail = () => {}
} = options
if (!fontUrl) {
console.warn('[字体加载] 未提供字体 URL')
return
}
console.log(`[字体加载] 开始加载字体: ${fontFamily}`)
my.loadFontFace({
family: fontFamily,
source: `url("${fontUrl}")`,
success: (res) => {
console.log(`[字体加载] 字体加载成功: ${fontFamily}`, res)
onSuccess(res)
},
fail: (err) => {
console.error(`[字体加载] 字体加载失败: ${fontFamily}`, err)
onFail(err)
}
})
// #endif
}
/**
* 加载多个字重的字体
* @param {Object} options 配置选项
* @param {string} options.fontFamily 字体名称
* @param {Array} options.fonts 字体配置数组 [{weight: 400, url: '...'}, ...]
*/
export function loadMultipleWeights(options = {}) {
const { fontFamily = 'PingFang SC', fonts = [] } = options
if (fonts.length === 0) {
console.warn('[字体加载] 未提供字体配置')
return
}
// #ifdef MP-WEIXIN
fonts.forEach(font => {
loadWechatFont({
fontFamily: `${fontFamily}-${font.weight}`,
fontUrl: font.url,
onSuccess: () => {
console.log(`[字体加载] ${fontFamily} ${font.weight} 加载成功`)
},
onFail: (err) => {
console.error(`[字体加载] ${fontFamily} ${font.weight} 加载失败`, err)
}
})
})
// #endif
// #ifdef MP-ALIPAY
fonts.forEach(font => {
loadAlipayFont({
fontFamily: `${fontFamily}-${font.weight}`,
fontUrl: font.url,
onSuccess: () => {
console.log(`[字体加载] ${fontFamily} ${font.weight} 加载成功`)
},
onFail: (err) => {
console.error(`[字体加载] ${fontFamily} ${font.weight} 加载失败`, err)
}
})
})
// #endif
}
/**
* 使用示例:
*
* // 在 App.vue 的 onLaunch 中调用
* import { loadWechatFont, loadMultipleWeights } from '@/utils/loadMiniProgramFonts'
*
* export default {
*   onLaunch() {
*     // 方式 1: 加载单个字体
*     loadWechatFont({
*       fontFamily: 'PingFang SC',
*       fontUrl: 'https://your-cdn.com/fonts/PingFangRegular.ttf',
*       onSuccess: () => {
*         console.log('字体加载成功')
*       }
*     })
*
*     // 方式 2: 加载多个字重
*     loadMultipleWeights({
*       fontFamily: 'PingFang SC',
*       fonts: [
*         { weight: 400, url: 'https://your-cdn.com/fonts/PingFangRegular.ttf' },
*         { weight: 500, url: 'https://your-cdn.com/fonts/PingFangMedium.ttf' },
*         { weight: 600, url: 'https://your-cdn.com/fonts/PingfangSemibold.ttf' }
*       ]
*     })
*   }
* }
*/

提供了可选的小程序网络字体加载方案,包括:

  • loadWechatFont() - 微信小程序字体加载
  • loadAlipayFont() - 支付宝小程序字体加载
  • loadMultipleWeights() - 批量加载多个字重

5. 创建平台测试页面

文件: src/pages/font-platform-test.vue

提供了跨平台字体渲染测试页面,可以:

  • 检测当前运行平台
  • 显示平台字体支持情况
  • 测试不同字重的渲染效果
  • 显示预期表现说明

平台表现对比

平台@font-face字体加载显示效果性能影响
H5✅ 支持加载自定义字体PingFang SC需要下载字体文件
iOS App✅ 支持使用系统字体PingFang SC无额外开销
Android App✅ 支持加载自定义字体PingFang SC需要打包字体文件
小程序 iOS❌ 不支持使用系统字体PingFang SC无额外开销
小程序 Android❌ 不支持使用系统字体Roboto/思源无额外开销

使用建议

当前配置(推荐)

适用于大多数场景,无需额外配置:

// App.vue - 无需修改
export default {
onLaunch() {
// 不需要额外的字体加载代码
}
}

优点:

  • ✅ H5 和 App 显示一致
  • ✅ 小程序使用系统字体,性能最佳
  • ✅ 无需额外配置
  • ✅ 代码简洁

缺点:

  • ⚠️ 小程序 Android 无法显示 PingFang SC

小程序网络字体方案(可选)

如果必须在小程序 Android 上显示 PingFang SC:

// App.vue
import { loadWechatFont } from '@/utils/loadMiniProgramFonts'
export default {
onLaunch() {
// #ifdef MP-WEIXIN
loadWechatFont({
fontFamily: 'PingFang SC',
fontUrl: 'https://your-cdn.com/fonts/PingFangRegular.ttf',
onSuccess: () => {
console.log('字体加载成功')
}
})
// #endif
}
}

前置条件:

  1. 将字体文件上传到 CDN(支持 HTTPS)
  2. 在小程序后台配置 CDN 域名白名单
  3. 字体文件大小 < 2MB

优点:

  • ✅ 所有平台显示一致

缺点:

  • ⚠️ 增加首屏加载时间
  • ⚠️ 需要 CDN 和域名配置
  • ⚠️ 字体文件大小限制

测试方法

1. H5 测试

# 启动 H5 开发服务器
npm run dev:h5
# 访问测试页面
http://localhost:8080/#/pages/font-platform-test

在浏览器开发者工具中:

  • Network 面板查看字体文件加载
  • Elements 面板查看元素的 Computed 样式

2. 小程序测试

# 微信小程序
npm run dev:mp-weixin
# 支付宝小程序
npm run dev:mp-alipay

在小程序开发者工具中:

  • 使用 iOS 模拟器测试系统 PingFang SC
  • 使用 Android 模拟器测试降级字体

3. App 测试

# iOS App
npm run dev:app-ios
# Android App
npm run dev:app-android

在真机或模拟器上测试字体渲染效果。

性能优化建议

1. 字体文件优化

如果字体文件过大,可以:

# 安装 fonttools
pip install fonttools brotli
# 提取常用字符子集
pyftsubset PingFangRegular.ttf \
--text-file=common-chars.txt \
--output-file=PingFangRegular-subset.ttf

2. 使用 WOFF2 格式(H5)

WOFF2 比 TTF 小 30-50%:

@font-face {
font-family: 'PingFang SC';
src: url('/static/fonts/PingFangRegular.woff2') format('woff2'),
url('/static/fonts/PingFangRegular.ttf') format('truetype');
font-weight: 400;
}

3. 按需加载字重

只加载常用的 3-4 个字重,而不是全部 5 个。

4. 字体预加载(H5)

index.html 中添加:

<link rel="preload"
  href="/static/fonts/PingFangRegular.woff2"
  as="font"
  type="font/woff2"
  crossorigin>

常见问题

Q1: 为什么 H5 没有加载字体文件?

可能原因:

  1. 页面上没有元素使用 font-family: 'PingFang SC'
  2. 字体文件路径不正确
  3. 浏览器缓存问题

解决方法:

  1. 检查 App.vue 中是否设置了全局字体
  2. 检查 fonts.scss 中的路径
  3. 清除浏览器缓存后重试

Q2: 小程序 Android 能否显示 PingFang SC?

默认情况: 不能,会降级到系统默认字体。

解决方案: 使用网络字体加载(参考上文"小程序网络字体方案")。

Q3: iOS App 会加载字体文件吗?

不会。 iOS 系统自带 PingFang SC,浏览器会优先使用系统字体,不会下载字体文件。

Q4: 字体文件太大怎么办?

优化方案:

  1. 使用字体子集化(只包含常用字符)
  2. 使用 WOFF2 格式(H5)
  3. 只加载必要的字重(3-4 个)
  4. 考虑使用系统字体栈

相关文档

自定义字体跨平台指南

平台兼容性分析

当前实现的平台表现

平台@font-face 支持PingFang SC 系统字体实际效果
H5✅ 完全支持❌ 无加载自定义字体文件
iOS App✅ 支持✅ 系统自带优先使用系统字体
Android App✅ 支持❌ 无加载自定义字体文件
微信小程序❌ 不支持iOS: ✅ / Android: ❌iOS 用系统字体,Android 用默认字体
支付宝小程序❌ 不支持iOS: ✅ / Android: ❌iOS 用系统字体,Android 用默认字体

问题说明

1. 小程序平台的限制

微信小程序不支持 @font-face,但提供了 wx.loadFontFace() API:

// 微信小程序中加载网络字体
wx.loadFontFace({
family: 'PingFang SC',
source: 'url("https://your-cdn.com/fonts/PingFangRegular.ttf")',
success: console.log,
fail: console.error
})

限制:

  • 字体文件必须是网络地址(不能是本地文件)
  • 需要配置域名白名单
  • 字体文件大小有限制(建议 < 2MB)

2. Android 系统没有 PingFang SC

Android 系统默认字体是 Roboto思源黑体,没有 PingFang SC。如果要在 Android 上显示 PingFang,必须:

  • 打包字体文件到 App
  • 或通过网络加载字体

3. iOS 系统自带 PingFang SC

iOS 9+ 系统自带 PingFang SC,直接使用 font-family: 'PingFang SC' 即可,不需要加载字体文件。

推荐方案

方案 1:条件编译 + 平台适配(推荐)

针对不同平台使用不同的字体策略:

/* src/style/fonts.scss */
/* H5 和 App 平台使用 @font-face */
// #ifndef MP
@font-face {
font-family: 'PingFang SC';
src: url('/static/fonts/PingFangRegular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'PingFang SC';
src: url('/static/fonts/PingFangMedium.ttf') format('truetype');
font-weight: 500;
font-style: normal;
font-display: swap;
}
// 其他字重...
// #endif
/* 小程序平台使用系统字体 */
// #ifdef MP
/* 小程序不支持 @font-face,iOS 使用系统 PingFang,Android 使用默认字体 */
// #endif

App.vue 中的全局样式:

/* 全局字体设置 - 跨平台兼容 */
page,
view,
text,
button,
input,
textarea {
/* iOS: 使用系统 PingFang SC */
/* Android: 使用自定义 PingFang SC(如果加载成功)或 Roboto */
/* 小程序: iOS 用 PingFang SC,Android 用默认字体 */
font-family: 'PingFang SC', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Roboto', 'Noto Sans SC', 'Microsoft YaHei', sans-serif;
}

方案 2:使用网络字体(适合小程序)

如果需要在小程序中使用自定义字体:

// App.vue - onLaunch
export default {
onLaunch() {
// #ifdef MP-WEIXIN
// 微信小程序加载网络字体
wx.loadFontFace({
family: 'PingFang SC',
source: 'url("https://your-cdn.com/fonts/PingFangRegular.ttf")',
success: () => {
console.log('字体加载成功')
},
fail: (err) => {
console.error('字体加载失败', err)
}
})
// #endif
// #ifdef MP-ALIPAY
// 支付宝小程序类似
my.loadFontFace({
family: 'PingFang SC',
source: 'url("https://your-cdn.com/fonts/PingFangRegular.ttf")',
success: () => {
console.log('字体加载成功')
},
fail: (err) => {
console.error('字体加载失败', err)
}
})
// #endif
}
}

注意事项:

  • 字体文件需要上传到 CDN
  • 需要在小程序后台配置域名白名单
  • 字体文件会增加首屏加载时间

方案 3:使用相似的系统字体(最简单)

不使用自定义字体,而是使用各平台的优质系统字体:

/* 使用系统字体栈 */
page,
view,
text {
font-family:
-apple-system,           /* iOS/macOS 系统字体(包括 PingFang SC) */
BlinkMacSystemFont,      /* macOS Chrome */
'Segoe UI',              /* Windows */
'Roboto',                /* Android */
'Noto Sans SC',          /* Android 中文 */
'Helvetica Neue',        /* 旧版 iOS */
'Microsoft YaHei',       /* Windows 中文 */
sans-serif;              /* 后备字体 */
}

优点:

  • 无需加载字体文件,性能最佳
  • 跨平台兼容性好
  • 用户体验一致(使用系统原生字体)

缺点:

  • 不同平台显示的字体不完全一致
  • 无法精确控制字体样式

实际测试建议

测试清单

  • H5 浏览器

    • Chrome DevTools 网络面板查看字体加载
    • 检查字体渲染效果
  • iOS 真机/模拟器

    • 检查是否使用系统 PingFang SC
    • 测试不同字重显示
  • Android 真机/模拟器

    • 检查自定义字体是否加载成功
    • 测试字体文件大小对性能的影响
  • 微信小程序

    • iOS 设备:检查系统 PingFang 显示
    • Android 设备:检查降级字体显示
  • 其他小程序平台

    • 支付宝、抖音、百度等

性能优化建议

1. 字体文件优化

# 使用 fonttools 压缩字体文件
pip install fonttools brotli
# 提取常用字符子集(减小文件大小)
pyftsubset PingFangRegular.ttf \
--text-file=common-chars.txt \
--output-file=PingFangRegular-subset.ttf \
--flavor=woff2

2. 使用 WOFF2 格式(H5)

WOFF2 比 TTF 小 30-50%:

@font-face {
font-family: 'PingFang SC';
src: url('/static/fonts/PingFangRegular.woff2') format('woff2'),
url('/static/fonts/PingFangRegular.ttf') format('truetype');
font-weight: 400;
font-display: swap;
}

3. 字体预加载(H5)

<!-- index.html -->
    <link rel="preload"
    href="/static/fonts/PingFangRegular.woff2"
    as="font"
    type="font/woff2"
    crossorigin>

4. 按需加载字重

只加载常用的字重(400、500、600),避免加载所有字重:

/* 只加载 3 个常用字重 */
@font-face {
font-family: 'PingFang SC';
src: url('/static/fonts/PingFangRegular.ttf') format('truetype');
font-weight: 400;
}
@font-face {
font-family: 'PingFang SC';
src: url('/static/fonts/PingFangMedium.ttf') format('truetype');
font-weight: 500;
}
@font-face {
font-family: 'PingFang SC';
src: url('/static/fonts/PingfangSemibold.ttf') format('truetype');
font-weight: 600;
}

总结

当前的跨平台优化方案:

已完成:

  • 条件编译优化(小程序不加载无效代码)
  • 完整的字体降级方案
  • 详细的平台说明文档
  • 可选的小程序网络字体加载工具
  • 平台测试页面

推荐配置:

  • 保持当前实现(无需额外配置)
  • H5 和 App 使用自定义字体
  • 小程序使用系统字体

性能表现:

  • H5: 需要下载字体文件(一次性)
  • iOS App: 无额外开销
  • Android App: 字体文件打包到 App
  • 小程序: 无额外开销

这个方案在保证视觉一致性的同时,兼顾了性能和开发成本。

posted @ 2025-12-15 13:07  yangykaifa  阅读(16)  评论(0)    收藏  举报