中文 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 使用体验,有兴趣的朋友也不妨试个水。

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

Read More

多媒体大作业:《龟背上的旅——中国古代数学》

Link: https://www.bilibili.com/video/av2594297/

呶,从《周易》到周髀,从勾股到割圆,
中国古代的数学,我就在这里讲给你听。

好啦,只是一份三人合作的多媒体大作业,我出于过度自信把它上传到了~茵特奈特~这的伟大的平台之上。
请抱着~能把故事讲成这样也挺不容易的/想不到UP主居然是个天才/偶尔从另一个角度审美也不无优处~的心态观看。
而且,你要是实在看不下去,我完全不介意你在这里骂我!

因为……
话说回来,我这个博客呀,除了我的自言自语,已经一周年没有新评论了。
( ??? .?.? ??‵)y (一周年啊,好羞耻啊……!)

我画了一条鱼

P.S. 版权声明:由于这个视频真的是出于学习目的制作,故有未经授权而使用 Adobe CS6、Autodesk 3ds Max 等商业软件以及方正、昆仑、造字工房等商业字体的行为,背景音乐《明月杭州夜》为作曲家李志辉的新世纪音乐作品,在此对以上个人及公司表示歉意与感谢。

Read More

那段无与伦比的美丽

那就模拟一段四人寝室的闲谈来讲述一件事吧。

甲:……你的MP3又那么闪!
我:嘿嘿……
甲:话说,你在听什么……(看电脑屏幕)《无与伦比的美丽》……我去,你居然听苏打绿的歌!
我:没有啦……只是刚才乙哼的那首歌让我觉得很像这首歌的前奏!
乙:诶?《无与伦比的美丽》吗?我唱的不是这首啊!
我:嗯,确实不是,你只是跑调的比较严重……
乙:⊙_⊙
我:也没有啦,只不过是这个歌啊,有个典故,它让我想起了一群故人。
乙:⊙_⊙
甲:什么典故?
我:以前初中我们班里有一对比较有趣的双胞胎男生中的一个,他们的名字也很有意思,一个叫X经达,一个叫X纬达。在我们班的那个是经达。
乙:然后呢?
我:那个时候已经初三的期末了,我和另外一个很有趣、很好而且还很好看的女生相处的很好,她叫J,因为当时要一起争取高中的保送,所以一起学习什么的,走得相当近。我们还每天傍晚放学去拜学校里的一棵树,因为我们觉得那是一棵神树!
甲:呃……
我:然后就聊到了啊,你最喜欢班上的哪个男生,我就说我喜欢X经达。她说她也是。然后,我们就笑了,然后开始想那可怎么办,两个女生喜欢上同一个男生了啊。于是我就想了一个好主意,那就你喜欢经达,我喜欢纬达好啦!这样都能分到一个!她也觉得这个主意棒呆了!还说,那就这么定了,你就喜欢纬达吧,我喜欢经达!!
乙:噢~
我:但我其实和那个纬达一点都不熟。但结果后来到了高中,经达和J没有分到一个班,我和纬达居然都分到一个班了!
乙:喔~那然后发生了什么!
我;什么都没有发生……我和他到了毕业还是半点都不熟……然后我和J后来不在一个班所以也不太联系了。
乙:……
我:但这个故事的关键点在于,我前两天刚知道经达和J居然真的在一起了!!居然初中我们聊的天成真了!
乙:那纬达呢?
我:纬达现在和我们班的另外一个女生Q在一起了,她的名字里和我一样也有一个“怡”,是不是还算是很巧!
乙:这样啊……那你现在还喜欢经达和纬达吗?
我:那我一直以来对他们都有好感啊!不过这没什么,我只是神奇于他们四个居然真的实现了这样的恋爱发展。那个J真的是一个很好的人,我现在还觉得她真的很有趣!Q和J也很像,都是那种我一交流就知道很有想法的女生!他们都是很好的人啊,所以有这样的进展我很欣慰啊……嗯对了,经达的QQ名就叫“无与伦比的美丽”,然后这个典故就是这样。
……

以上就是关于这件事的一段假想的闲谈,然而对这件事,我却不会真的就这样闲聊。
不知怎么的,他们四个真的都是很好的人,他们就这样在一起我也觉得就应该这样。但其实我的感受并不是我说的“不过这没什么”,被这样一段有趣的故事落在外头,现在想起来,确实觉得自己很捉急啊。

Read More

玉米饼上放盐放糖

桃李年华

五月初,害羞地知道我小站的所有文章被人「情不自禁」地看完了,而吾本人还恬恬地被询了芳名去。本想立刻在我的地盘上再写一篇横行霸道的日志来显示我的热情与喜悦,可却怕有是特意写给那某人的暗示,反叨扰了对方,更掉了矜持!

五月八,二十岁生日。先前特别担心的是,我还没做好准备,怎么就到古言之桃李年华了。听上去、看上去、说起来、数起来多么重要的二十岁啊,就这么呼啸着既不靠边、也不减速地到站了?然而,既知道我的文章写得那么吸引人以至于被人「情不自禁」地看完了,那我自己自然也要自豪而又自信地刷上一通。于是发现,在那篇最初的 Hello, world 里我分明已经把人生按七年一阶段地划分好了。然后我就不愁了,唔啊,距离我人生第三个七年的结束还有一年,那么看来不必急赶在这两天给自己一个交代了;关于走向人生的第四个七年,我还能用一整年来准备。(嗯倒和我十九岁生日时想得一模一样。)

五月中,哈哈哈,我的又一个iPad到手啦。早就到手啦,四月底就开始物色啦,二手哒,便宜哒,穿着裙子去一手交钱一首交货哒,买给自己哒,用到现在没坏哒,虽然也不是怎么好哒;反正我的进水手机已经学会自动关机啦,不就是想给我个机会嫌弃它嘛——它虽说无端地重启、死机、发热、耗电、屏幕按不到边、卫星定不到位、插卡不见信号、流量半点用不了,然而我一直以来都是忍它、让它、由它、避它、耐它、敬它、不要理它,再待几年我且看它——呐(?·_·`),这一切并没有好转。

其实说起了,我的手机MX2进水罢工已经是一年半前的事情了,而我买下一部诺基亚红壳直板手机又买了一部节操手机也已经是一年半前的事情了,接着节操手机被摔得没信号又是近一年半前的事情了,不幸的节操手机的公司破产也是差不多一年半前的事情了,于是我开始拿诺记功能机当主力机是从一年半前就开始的事情了,而我不久后发现进过水的MX2还能开机连WiFi是一年多前的事情了,那么后来我出门会带上三只手机也是从那以后的事情了。

执诺记功能机走天下的感受是很神奇的,在当下移动互联网的时代,它意味着不被即时联系到、不在当场参与、不可随时迎上更多信息,颇有点搬到瓦尔登湖隔壁去的意思。当然我是没有遗世独立的打算的,校园WiFi的气息虽微弱,终究能让我的两部智能机苟延残喘。虽不被及时联系到,也总归能被联系到;虽不在当场参与,也总归在散场后参与了;虽不可接住随时纷纷迎面而来的各种信息,也总归在风潮之后拿网兜一挥收拾干净了那些各种。冒昧借用已逝者遗作名,我这一年半的生存状态,似站在两个世界的边缘。一个世界吵得累人,另一个世界静得乏味。所以我自认为站在这样两个世界的边缘,只切向前进,而不愿前进的方向分离出哪一个世界的法向量。

所以我自认为不买一部新的、好用、没毛病的智能机,是为了好好地站稳在上面所描述的两个世界的边缘,而不是因为没钱。

五月下,我看电影的开始,结束啦。我所谓之开始,是崭新的开始;我所谓之结束,只是段落的结束。以前,小时候,我不看电影呀,以为看电影是奢靡浮华的消遣哇。那时,小时候,也不知从哪里得知,教父三部曲是经典,于是我看了十分钟看到睡着。后来,小时候,我就不特别看电影了,下得慢得让人困,看不懂得让人烦。偶尔,小时候,我会去看那么两部,柯南的剧场版,它们都很好看,让我看得很明白。但我说这些话时却并没有什么底气。

//呃……写到这里,我忽然觉得快被我文字的依靠句式重复来推出节奏感的写作方式给熄灭了。算了,别管别管,这种翻来倒去、推推进进,估计是选修课害得十二平均律听太多了。

但是今年初,大概是受了梁边妖传说中两万阅片量的刺激,亦或者是多看书城里下了新的一辑知乎周刊结果里头提到的电影我半部都没看过,让我愤怒真不知道是我混账还是这个世界混账!然后我就气鼓鼓地去看电影了。借着豆瓣与寒假、上课、小长假,打了一百个勾。

我的豆瓣观影报告

看到没有!我属于骨灰级影迷!我很接受大家的跪拜!我是大神!
(含糊不明)偶尔看电影倒也不赖。

五月底,快到了。To Do 的事情多的时候,用 To-Do-List 好像更烦了。在四月底的时候,我就打了一篇草稿,是关于我这些年来所受的苦与难的,是真的真的苦与难!然而最近的大难还没结束,我就汲汲于展示自己的疮疤,日后就是自己看到了也同样会觉得不是什么滋味,虽然,那一篇草稿的主旨大意在于“家里出了这么大的事,我居然第一反应是天将降大任于我也——那我真是一个多么洒脱的人儿啊”,即,没心没肺地用苦难来夸奖自己。呃,这样的文章写出来就算了,要发布那还是省省了。

可我写现在笔下这篇的本意,其实正是在于不露马脚地把那一篇受难记给发布出来,连标题都是为它取的。连怎么点题我都想好了,即忽然笔锋一转,淡淡讲起童年的一个故事——我曾以为我有在厨房里舞蹈的天赋(看,我还是讲出来了),于是我去超市里买了一包玉米粉,用玉米粉做了一个玉米饼,把玉米饼放到微波炉里烤了烤,微波炉烤出来的玉米饼非常地难吃,这股难吃我想了想认为应该源自于没放盐于是我放了盐,放了盐的玉米饼但其实还是很难吃,这新的一股难吃我又想了想认为应该源自于没放糖于是我又放了糖,放了糖的玉米饼但居然变得更难吃了,难吃到我实在吃不下去又不舍得扔。

这就是玉米饼上放盐放糖的故事,我讲这个故事的目的在于做一个比喻——我现在的生活好像一个玉米饼,有盐,即是咸的,谐音闲,就是明明有空做自己喜欢的事情;也有糖,取其象征意味,即有不少 sweet·sweet 的事情发生在身边。可这个玉米饼,就是很难吃。

在那个童年故事里的玉米饼,最后被我妈扔到了垃圾桶去;如果我的生活真的是一个玉米饼的话,我还是希望不要有人看不下去也把它扔到垃圾桶,但愿有厨艺高超到能用各种奇怪食材做出好菜来的师傅告诉我怎么把一个玉米饼做得好吃,或者容我自己再试着加点辣椒、酱油、葱花调个味什么的吧。

五月完。

Read More