前端自定义字体总结

87 阅读4分钟

最近,在做一个嵌入在原生app中的H5项目,其中app中的大部分功能都是需要在H5中实现的,其中有这么一个需求,字体遇到中文用中文字体,遇到英文用英文字体,遇到韩文用韩文字体,针对以上踩过的坑我们来好好总结下。

业务背景就是,中文用中文,英文用英文,韩文用韩文,如果互相有其他夹杂的情况,对应的字体也是指定的字体,意思中文中的英文,中文是中文字体,英文是英文字体,同等其他字体。说说目的吧,前端要解决自定义字体是因为字体包太大和不同文字用不同字体的目的。

1.开发阶段压缩

如果你的项目只是一个静态项目,页面中所有就字体都是确定已知的,并不需从服务端获任何新的未知文字,那么可以考虑下,fontminfont-spider 等等工具将现有的字体代码通过已知体量大的目标字体库中在开发阶段提取出需要的文字生成一个新的字体包从而最大限度减少体积,但是这个仅限于静态项目(文字可确定,数量可确定,服务端传输的文字已知),如果你的项目中客户端服务端文字都是未知的,那么这种方法是行不通的

2.FontCreator

如果项目不是静态的,创建新的轻量剔除过的的字体包,使用FontCreator创建生成新轻量无冗余的字体包,删除用不到的字体,这是一款国外的软件,收费的,少部分功能是免费的(首次免费三十天),界面如下

image.png 操作也不是很难就是有点烦,手动一个个用不上的文字,或者从导入其他字体包,讲其他字体包用到的文字复制替换掉现有字体包的文字,这种方式是目前最靠谱的。

举例:思源A字体包中有‘你’,‘好’,‘A’,‘B’,思源B字体包中有‘你’,‘好’,‘A’,‘B’,那么我就可以通过FontCreator工具将思源B中的矢量文字‘A’和‘B’替换掉思源A中的‘A’,‘B’,然后替换好后导出新的字体包思源C,那么在使用新字体包思源C的时候,如果遇到项目中遇到文字A就实际使用的是原始思源B中的矢量文字‘A’,遇到‘你’的时候,实际用的是思源A中的‘你’,通过这样的方式原始思源字体在15M左右,替换和删除无用的矢量文字及符号等等,然后导出为压缩为woff格式,基本字体大小能控制在几M甚至是几百KB,但是话说这活儿不是一般人能干的,实际的开源的思源加粗字体包15M左右,大约7~9万个矢量字符,有兴趣的还是得搜下教程吧...

另外,在线字体格式转换transfonter,将小体量的ttf或者格式字体转换成适合web的woff字体,也可以通过FontCreator完成,但是这30天体验,过期收费的否则无法导出字体包

补充:如果还有这样的需求,需要控制字体的动态加载,我们可以使用 font-face fontfaceobserver来优化现有

3.原生共享字体

共享字体,那还有没有一种可能,毕竟在web端解决的是字体太大的问题,而在app端不存在这样的问题,app端直接引入字体包,毕竟app端不太在乎包体积大的问题,客户是直接下载到手机上的,然后web端调用app的字体包实现上述需求,这个功能我们再安卓上做了尝试发现确实可行的,我们做法是先通过FontCreator生成新全量字体包已经实现了中英韩三种语言的,然后原生app向webview共享字体包

@font-face {
	font-family: 'test';
	src: url('@/static/font/en/test-Bold.woff') format('woff2'),
		url('@/static/font/en/test.woff') format('woff'),
		url('/android_asset_font/normal.ttf');
	font-weight: normal;
	font-style: normal;
	font-display: block;
}

而安卓端,重写WebViewClient 的shouldInterceptRequest方法在webview请求安卓目录下的,资源时候将字体包给webview即可,这里可以和安卓的同学沟通下,实践不是很麻烦。

而针对ios端,ios的伙伴就大无语了,ios实现不了,然后通过JSBridge来实现,在web这边写一个custonFont方法,ios在webview加载完成之后调用custonFont方法讲字体包以文件流方式传输给webview,但是实际结果很遗憾,方法是可行,但是页面直接卡爆了,最终不了了之。只能兜底方式,font-face,css执行顺序是从下到上,首先执行的是

url('/android_asset_font/normal.ttf');

其次是

url('@/static/font/en/test.woff') format('woff'),

最后是

url('@/static/font/en/test-Bold.woff') format('woff2')

但是可惜ios端字体包大的问题还是没有得到根本解决...