中文 Web Font 使用体验之“有字库” Web Service 接口定制

中文 Web Font(在线字体)一直以来都是许多对字体运用有执念的网页设计师心中的大洞。正如腾讯 ISUX 在设计师的春天:中文 Web Font 解决方案一文中所述,一直以来,如果想在网页中选用自定义字体,通常会采用图片的形式来实现,但造成的问题有:

  1. 制作与维护成本很高。切图繁琐、高清屏适配繁琐、合并雪碧图更繁琐,后期修改更加繁琐。
  2. 用户体验差。导致网页不支持选中、复制、搜索、翻译、矢量缩放,也会影响视障用户使用读屏器操作网页。
  3. 带来更多带宽消耗。导出的图片体积随着文本面积增加,且字形无法重复利用,这消耗着大量的服务器资源

但为何 Google 能推出免费的英文字体 Web Font 云托管服务,而中文字体却迟迟无人做到呢?

英文字体文字部分由26个字母组成,所以字体文件通常不会太大;而中文汉字数量总共约有九万左右,国标(GB)字库有6763字, 而根据《现代汉语常用字表》统计数据,常用汉字也要有3500个左右。中文字体文件通常都会几M的大小,参照现在中国的网络环境,显然不适合在项目中使用。

一句话来说,就是中文字体太大。

但如果你试着访问苹果中国官网,可以发现它的页面在 Windows 电脑上同样可以显示 Mac OS 自家最新的“苹方”中文字体。(苹方未出之前,网站字体是同样苹果的华文黑体。)

苹果中文官网-苹方字体

那既然中文字体这么大,那苹果是怎么做到在网页中使用且不影响用户体验呢?(其实是影响了的,有时候字体加载得比图片还慢。)这又有几方面的原因

  1. 这些字体并非是 "完整的", 我们一般称之为子集化字体. 以这三个字体文件而言, 它们仅含有 2665 个汉字, 远少于简体中文字符集最低标准 GB2312 的汉字数量 - 6763 个. 不过非汉字的其它文字及符号倒是很多, 共有 1493 个, 但这些东西没有汉字占空间就是了。
  2. 黑体相比起其它类字体 - 如宋体, 书法类字体等 - 占的空间要小, 这是因为它的笔划设计比较简洁, 使得矢量节点比较少。
  3. WOFF 是专为 web 应用而制定的格式, 它拥有体积更小的特点. 将这三个 woff 的 URI 结尾改成 "ttf" 可以下载到相同内容的 TTF 格式字体, 体积要大一倍以上。

对于我们来说,最有参考价值的就是第一点,即只保留字体文件中的有用字,舍弃无用字。

而现在,这一点已经有了各种各样的实现,例如百度的 fontmin,腾讯的字蛛。但这些都需要一些设计师比较难把握的技术支持,比如说大概要在服务器安装个 Node.js……所以也出品了一些前端直接能用的网页字体托管,比如 justfont有字库。但出于 justfont 在博主这边访问莫名的慢,且为收费服务,因此对于我等博客小站还是略有些不值当。

于是,在此情境下,我于是选择了有字库的在线字体服务。其具体使用,例如注册、字体选择等并没有什么特别值得提出的难点。但到底怎么搬到网站上,它提供了三种方式。

第一种,CSS模式。你只需往文本框中输入你需要使用的文字,然后点击生成,将所指示的CSS或JS添加到自己网站需要的部分即可。不过,这种方式只适合于静态文本,对于个人博客来说,就比如网站的标题(你总不可能三两天就把网站改个名吧)、导航条以及某些其他不常改动的提示文字等。如果后期真的需要修改文字,只需要在有字库后台编辑即可。

有字库CSS模式-1

有字库CSS模式-2

这种方式使用方便,没什么限制,除了不支持动态文字没什么不好的。然而,对于博客来说,数不胜数的就是动态文字。文章的标题,每一篇都不一样吧;文章的内容,总不能全是复制粘贴吧。确实可以往CSS模式里多搬进去几个字,把整个字符库搬进去也未必不可,但是这样就没有中文 Web Font 技术的意义了。所以,可能需要采用另一种模式。

第二种,卢教模式。不要在意它奇怪的名字,反正这种模式对于虽然经常修改,但idclass的数据源不变的文字来说有奇效。我本来以为这种模式会比较适用于类博客的动态网站,然而,仅就博主我个人情况,当我将它应用到日志标题上时,虽然在日志单页上能达到部分预期效果(首次刷新不加载并不算问题),但在调用了多篇文章标题的主页index.php上问题就大了,经常出现的情况是第一篇文章的标题有自定义字体的效果,而后几篇通通失效。我大致感悟了一下这种模式的机理后就放弃了使用。

如果到此为止,我只选择在站点标题、导航或者某些装饰文字使用特殊字体,那这篇文章也没有发出来的必要了。但我思前想后还是不甘心,于是决心再尝试一下最后一种方法。

第三种,接口定制(Web Service 引用方式。这个模式适合大型动态网站,由于 Typecho 的cid属性格式为int而非guid,所以如果有动态内容需要调用自定义中文字体,就需要通过有字库提供的MD5方法,即根据不同的文章标题以及你的账户、密码,生成不同的MD5值以及后台字体文件。

根据其使用说明,ASP.NET 服务器上只需:

  1. 添加 Web Service 引用:http://www.youziku.com/webfontcreator.asmx?WSDL
  2. 调用效果生成方法:
    有字库 Web Service 调用代码
  3. 利用生成的MD5值,调用CSS或JS代码即可,和第一种模式相同。

然而,对于PHP的后端,想要实现引用,还需要利用SOAP模块来实现。关于PHP5调用 Web Service,更一般的代码教程,可参考此文。经过阅读与学习,于是——例如,单纯的想要实现文章标题都采用自定义字体,一种低效、耗能、访问慢的方式(ASP.NET 引用代码合理演绎的结果)是——将 Typecho 主题中index.phppage.phppost.php等的文章标题引用字段

<h2 class="post-title"><a href="<?php $this->permalink() ?>"><?php $this->title() ?></a></h2>

扩充为

<?php
    $client = new SoapClient('http://www.youziku.com/webfontcreator.asmx?WSDL');
    $StrUserName = "mail@example.com";   //你的注册账号
    $PassWord = "yourpassword";          //你的注册密码
    $StrText = $this->title;             //文章标题
    $IntfontId = 19464;                  //字体编号,可参看字体的url
    $StrMD5 = $client->MD5creat(array('StrValue'=>$StrUserName.":".$IntfontId .":". $StrText))->MD5creatResult; 
    //根据用户账号、字体、文本内容生成MD5值
    $WebfontcreatByMD5 = $client->WebfontcreatByMD5(array('StrMD5'=>$StrMD5, 'StrText'=>$StrText, 'IntfontId'=>$IntfontId, 'StrUserName'=>$StrUserName, 'PassWord'=>$PassWord)); 
    //在有字库后台根据MD5值、文本内容、字体、用户账号、密码生成字体文件
?>
<h2 class="post-title <?php echo 'css'.$StrMD5 ?>"><a href="<?php $this->permalink() ?>"><?php $this->title() ?></a></h2>
    <!-- 根据MD5值,为文章标题添加class -->
<script type="text/javascript" src="http://www.youziku.com/UserDownFile/webfont.js"></script>
<script type="text/javascript">WebFont.load({custom:{urls: ['http://www.youziku.com/webfont/CSS/<?php echo $StrMD5 ?>']}}); </script>
    <!-- 根据MD5值,通过JS异步加载字体 -->

相信我,这种方式是可行的,然而每篇文章显示时,都需要访问有字库后台生成MD5值、创建字体文件。
所以,还是相信我,这绝对不是什么好主意。

更好的办法是在发表文章或标题修改时,自动连接有字库后台生成字体文件,前台直接通过PHP计算MD5值,再调用JS即可。然而博主比较蠢,不会做插件,就不能自动了,只好手动了。想了个笨办法,写了个PHP文件,每回发表新文章,自己去把文章标题提交一遍。

<!DOCTYPE HTML>
<html><head><title>字体提交</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head>
<body>
<form action="font-submit.php" method="get" name="form1">
<div align="right">文本内容:</div>
<input name="StrText" type="text" id="StrText">
<input type="submit" value="Submit"></form> 
</body></html>

<?php 
    $client = new SoapClient('http://www.youziku.com/webfontcreator.asmx?WSDL');
    $StrUserName = "mail@example.com";   //你的注册账号
    $PassWord = "yourpassword";          //你的注册密码
    $StrText = $_GET['StrText'];         //键入的文本内容
    $IntfontId = 19464;                  //字体编号,我这里写死了,你也不是不能写活
    $StrMD5 = $client->MD5creat(array('StrValue'=>$StrUserName.":".$IntfontId .":". $StrText))->MD5creatResult; 
    //根据用户账号、字体、文本内容生成MD5值
    $WebfontcreatByMD5 = $client->WebfontcreatByMD5(array('StrMD5'=>$StrMD5, 'StrText'=>$StrText, 'IntfontId'=>$IntfontId, 'StrUserName'=>$StrUserName, 'PassWord'=>$PassWord)); 
    //在有字库后台根据MD5值、文本内容、字体、用户账号、密码生成字体文件
    echo "生成!"; 
?>

把上面PHP代码存为font-submit.php文件,上传到网站根目录下,通过http://yourdomain.com/font-submit.php访问,输入文字即可。当然,这一步和每发一篇文章就去登陆一下有字库,然后往CSS模式的文本框里输入一遍并没有什么差别。

字体上传

然后,将上文提到的 Typecho 主题中index.phppage.phppost.php等的文章标题引用字段

<h2 class="post-title"><a href="<?php $this->permalink() ?>"><?php $this->title() ?></a></h2>

扩充为

<?php
    $StrUserName = "mail@example.com";   //你的注册账号
    $StrText = $this->title;             //文章标题
    $IntfontId = 19464;                  //字体编号,可参看字体的url
    $StrMD5 = md5($StrUserName.":".$IntfontId .":". $StrText);
    //根据用户账号、字体、文本内容利用PHP直接生成MD5值
?>
<h2 class="post-title <?php echo 'css'.$StrMD5 ?>"><a href="<?php $this->permalink() ?>"><?php $this->title() ?></a></h2>
    <!-- 根据MD5值,为文章标题添加class -->
<script type="text/javascript" src="http://www.youziku.com/UserDownFile/webfont.js"></script>
<script type="text/javascript">WebFont.load({custom:{urls: ['http://www.youziku.com/webfont/CSS/<?php echo $StrMD5 ?>']}}); </script>
    <!-- 根据MD5值,通过JS异步加载字体 -->

其中,

<script type="text/javascript" src="http://www.youziku.com/UserDownFile/webfont.js"></script>

这句直接在header.php头部调用,可省去在index.php多篇文章重复调用的麻烦。最终示例如下,其中,导航部分通过CSS模式调用,文章标题即为 Web Service 模式:

导航(CSS模式)、标题(Web Service 模式)

以上就是我的个人博客中文 Web Font 使用体验,有兴趣的朋友也不妨试个水。

毕竟,中国汉字美如画。把她用丑了,就可惜了。

关键词:web font中文字体有字库web service接口定制

Previous Next

已有 2 条评论

  1. eteled eteled

    请教一下博主,我在博客中某一篇文章中想使用有字库的迷你简丫丫体,通过卢教模式。
    我在文字编辑器里这样写(代码我一窍不通,照着页面依葫芦画瓢):

    $youziku.load("#id1", "ef05f02789654db9930ae13bd52bb544", "minijianyaya");
    $youziku.draw();

    那些年的日子像松紧带,一会儿短一会儿又长。

    结果就是并没有什么效果。想请教博主,如何正确使用卢教模式。

    1. 这里的 #id1,有没有替换称为你自己的id呢?
      还有最近有字库的API好像更新了,有些旧的调用方式也可能已经失效了。

添加新评论

*设定头像请访问Gravatar