第一章 我们应该承认,汉字是不适应网络时代的
只从两点来证明:
首先,从来没有过一个完整的汉字字体。
英语只包含26个字母,构成一篇文章、一个网页所需的全部字符都包含在ASCII码表内,每个字符在计算机中只需要一个字节表示。而反观汉字,甚至没有定论究竟有多少个字。目前我们可以使用的汉字(包括日语、韩语中的)大约有8万个,Unicode中定义了7万多个,在中国大陆地区广泛使用的GBK编码收录了2万个,GB2312编码收录了6千多个,在香港、台湾广泛使用的BIG5编码收录了1.3万个。一般情况下这些编码标准都能满足人们的需求,因为我们日常使用中的汉字大约只有3500个左右。
但是使用不完整的字体总归会引发问题。如果计算机中不包含某个字的字形,那么用到它时一般会被打印成方块乱码,在wikipedia社区被叫做豆腐问题。这种现象大家应该多多少少都遇到过,在软件界面上、在网页上、在命令行终端上等等。2014年习近平主席访问德国,当地人打出的横幅上就有很多“豆腐”,对于不会中文的人来说,“方块字”和“方块”确实很难区分……
其次,字体文件太大。
打开你计算机的字体文件目录,按大小排序,最大的几个一定是汉字字体(如果你装了汉字的话)。其它文字的字体文件一般都是几十到几百KB,而到了汉字,最小也是好几个MB,我Mac中的“楷体”更是高达70MB。它们的大小差异来自于所收录的字符集大小,考虑到前文所述,如果真的有一个“完整汉字字体”,那肯定是要上百MB的。也许你会觉得无所谓,现在的硬盘很大很便宜,但是其它一些场景下,这个大小是无法接受的,例如需要被打包进软件,或者需要随网页发布。2011年我为Blender实现国际化系统时,为了支持中文,需要将一个3MB的字体嵌入到软件中,被社区认为是不可接受的。因为软件本身只有27MB,他们一直致力于控制软件的大小,可能仅仅为了节省1MB空间就付出过很多努力,完全无法容忍从“二十多兆”突然飙升至“三十多兆”。而本文将要讲到的WebFonts技术也面临相同的问题。这一技术会在加载网页时从服务器取得字体,完成网页渲染。Google已经提供了这样的在线字体服务,但是至今仍不包含中文字体。因为不可能让用户在浏览一个小网页时额外还需要下载一个好几MB的字体。抛开带宽成本不讲,光是下载时间就足以严重损害用户体验了。
我们是否应该放弃汉字,或者像我以前的想法——废除生僻字,统一只使用3000个常用字?虽然在一定程度上解决了上述问题,但是终究是不可取的。汉字从甲骨文至今已有三千多年了,经史子集、诗词歌赋,承载了整个中华文明的历史。而计算机、互联网出现才区区五六十年,要为了它改造汉字,似乎还有点冒进。所以作为以“知识分子”自居的程序员,我们应该利用起自己手中的技术。传承数千年的汉字到了我们手里,我们就要让它从这个“互联网时代”好好地活下去。
第二章 言归正传,干货来袭
WebFonts是一种新兴的解决网页上字体缺失问题的技术。目前主流的浏览器都支持以下CSS语法:
@font-face {
font-family: 宋体;
src: url(‘http://path.com/songti.ttf‘) format(‘ttf‘);
}
如果网页中用到了该字体,浏览器就会根据src去加载。Google已经提供了这样的在线字体服务[1],Wikipedia的运营者WMF(维基媒体基金会)也建立了自己的字体库。当然,由于上面提到的这些原因,它们都还没有提供中文字体支持。为了解决这一问题,在今年的Google Summer of Code项目中,我为mediawiki(也就是Wikipedia所使用的wiki系统)实现了“自动字体裁剪”,项目主页见[2]。该解决方案分为三个部分:
1.在服务器端通过钩子(Hook),在页面被输出前预先根据内容裁剪出字体文件,这些字体只包含了将要被输出的文字,因此非常小。具体的裁剪是使用一个第三方开源库php-font-lib[3],其裁剪出的字体在格式上还有些问题,于是又调用fontforge导出一次,进行修正。这是本项目一大需要改进之处。
2.页面被客户端加载后,css中对WebFonts的定义被修改为了类似:
@font-face {
font-family: 宋体;
src: url(‘http://path.com/FontRequest.php?font=songti‘) format(‘ttf‘);
}
注意其url部分,已经不再是静态的ttf文件,而是一个php脚本,我称其为“动态字体技术”
3.在服务器端,“动态字体请求”需要被返回正确的、裁剪后的文件。根据实验,通过重定向到一个静态字体文件:
<?php
header(“Location:$path_to_tailored_font”);
?>
或者通过修改MIME Type来返回二进制数据:
<?php
header( ‘Content-Type: application/octet-stream‘ );
header( ‘Content-Disposition: attachment; filename=songti.ttf‘ );
readfile( $path_to_tailored_font );
?>
都可以达到目的。在本项目中采用的是第二种方法,以避免多余的HTTP请求。
第三章 眼见为实
在完成了上述项目之后,我在基金会的Labs服务器群上搭建了一个测试站点[4],在首页大家可以看到,第二行字采用了“文泉驿微米黑”字体,该字体的完整文件有4.5MB,但是通过Debug工具发现该页面只需要加载20KB。而另一个测试页面[5],含有一首完整的《最炫民族风》,也只需要加载40KB左右。至此,WebFonts技术终于可以运用于中文!你可以放心地在页面上包含特殊的字体,包括自定义的艺术字,而不必担心用户没有安装这个字体、或者下载开销太大、或者需要导出为图片嵌在网页里。
作为验证,你也可以新建wiki页面(请勿修改供展示用的页面),写下这样的代码:
<p style="font-family:WenQuanYi Micro Hei”>SOMETHING YOU WANT</p>
就可以看到页面加载了经裁剪的、仅包含了你所使用的文字的字体。当然,裁剪操作有一定耗时,所以第一次访问时有延迟量。
第四章 通用化,另一种实现
给Wikipedia的项目业已完工,但是我认为这个功能是通用的,可以解决一些大难题。因此我把这项工作总结并迁移到了Github上[6],并且采用了更简洁的实现。即在客户端用JavaScript收集字体信息,用AJAX向服务器端发出请求。服务器端进行裁剪操作(如果没有命中缓存),然后返回各个裁剪后的字体的URL。客户端收到后,生成CSS代码附加到<head>末尾。WebFonts随后生效。
这个实现非常简洁,易于部署。项目中附有示例代码,演示网页见[7].
结束语
欢迎大家为自己的网站部署这套系统,我愿意提供力所能及的协助。希望有朝一日能够有一个一站式的、带自动字体裁剪功能的中文字体在线服务,为中文网络世界提供统一解决方案。
我的微博:@甜菜萧
我的LinkedIn: linkedin.com/in/xiaoxiangquan
[1] https://www.google.com/fonts
[2] https://www.mediawiki.org/wiki/Extension:UniversalLanguageSelector/Fonts_for_Chinese_wikis
[3] https://github.com/PhenX/php-font-lib
[4] http://fonttailor.wmflabs.org
[5] http://fonttailor.wmflabs.org/index.php/Test
[6] https://github.com/xiaoxq/webfonts-subsetting
[7] http://fonttailor.wmflabs.org/webfonts-subsetting