中文及亚洲语言在线字体按需加载方案:Dynamic subsetting
上网冲浪时注意到一个设计讲究的中文站点使用了在线中文字体来呈现内容(虽然它拉取的是很朴素的知名开源字体(思源/Noto 系列)而非其他商业设计字体,但效果确实不错)。这个网站的文字内容是从他处动态拉取的,这一点与某些静态商品宣传页不同,后者的文案内容是固定的,在设计阶段就大可把用到的字单独抽取出来准备好;而从网络请求观察发现,这个网站的字体是前端运行时由 js 按需加载的,用到了哪些字才拉取对应的字形(这是理想情况),断断续续加载了数个 400+KB 的数据分片。这个站点使用的在线字体来自 use.typekit.net,可知该在线字体服务提供商为现在已经改名为 Adobe Fonts 的 Typekit。(尽管如此,以下仍称其 Typekit)
众所周知,包括中文在内的亚洲语言(如 CJK)字体体积庞大,完整地在线加载有很多方面的困难。因此这次注意到有网站接入了中文(亚洲)在线字体按需加载技术,我很感兴趣。虽然这项技术应该已经诞生挺长时间了,但是它似乎始终未能铺开应用,甚至毫无存在感,何以见得呢?——到了 2020 年我才意识到这项技术的存在,而且在(中文)搜索引擎中几乎检索不到该技术的使用讨论和介绍(讨论应该只在业内小圈子,业外就没业余文章讨论了的样子)。所以我才写这篇博文提一下这个技术,希望能往搜索引擎里,为这项技术的关键词贡献一条没什么技术含量但聊胜于无的讨论,为后来的同为非从业人员的业余读者指路。
Typekit 的动态字体的请求数据不是明文的,充斥着变化多端的 hash hex 和 base64(标准解码得到非明文数据);私有协议。我只是纯路人,不是商业公司做竞品方案调研,对 OpenType 规范也不了解,就不考察技术细节了,做一个浅层的技术观察,并指路一些非常粗略的技术简介就溜咯。
Typekit 称这项技术为 Dynamic subsetting,名字很直观,我就把它译作“动态子字集”好了;写这篇博文时简体中文网内基本搜不到它,基本只能在商业字体网站的产品宣传中看到。显然它不仅需要前端收集要(额外)用到的字并发出请求,还需要后端能动态计算(提取字库)应答,前端还好,后端的计算和流量成本不低,不是人人都用得起的平民级的方案,无人问津很正常,不然什么简书、掘金、博客园、知乎肯定大把简介,特别是在自建博客之类的教程中。
接入 Typekit 在线 Web 字体服务需要 Adobe 账号(这很 Adobe CC)和订阅(无订阅的免费体验限制成勉强能用的水平)。可我并没有(订阅)账号,Typekit 还挺封闭的,没走多深入就需要登录,首页介绍都是非技术的漂亮话,他处也没什么资料。好在 Adobe 的用户手册里,有图文并茂的服务支持文章,让我可以远远地看 Typekit 的后台托管页面长什么样,顺便听一些公开的粗略的技术细节。
Adobe (Typekit) 官方对动态按需加载字体技术的介绍页在这:https://helpx.adobe.com/fonts/user-guide.html/fonts/using/dynamic-subsetting.ug.html。摘录了其中部分内容,如下。
Dynamic subsetting & web font serving/动态子字集与 Web 字体服务
Adobe developed dynamic subsetting to accommodate East Asian web font serving. The large size of East Asian fonts — well over 10,000 glyphs in most cases — otherwise makes it unrealistic to load these fonts on a website without significantly impacting the load time.
东亚字体的大小很大(普遍包含远超 10,000 个字形),网站加载这些字体,而且还不显著影响加载时间,是不现实的。针对上述特点和问题,Adobe 研发了“动态子字集”(dynamic subsetting)技术,以优化东亚 Web 字体服务。The dynamic subsetting watches for any change to the Document Object Model (DOM)— such as a news feed or a comments section — and then requests any new characters that need to be added to the subset. This way, instead of downloading an entirely new font, the font loading simply requests the additional glyphs and performs the update right in the browser.
“动态子字集”通过监听(watch) DOM (文档对象模型) 的变更(例如动态推送或评论等场景),然后请求需要追加到子集的新字符来实现。如此一来,字体加载只需请求需要补充的字形并直接在浏览器中执行更新即可,而非下载(重复包含已有字形的)新字体替换。……
Why do I see 404 errors from dynamic font serving in my web browser?/为什么浏览器提示动态字体请求出现 404 错误?
It is normal to see some 404 errors with dynamic web font serving.
有时动态 Web 字体请求返回 404 错误是预期内的正常现象。The dynamic font loading looks at the characters loaded into the page and checks to see if the font subset already exists for them on use.typekit.net, to speed up the font loading. If that subset doesn't exist yet, a 404 is returned. It is then created and the subsequent request to the same font subset is successful (200).
动态字体加载会检查加载到页面中的字符,并检查 use.typekit.net 上是否已存在该字体子集,以加快字体加载速度(译者注:use.typekit.net 是 typekit 的 CDN 加速节点);如果该子集尚不存在,则返回 404。待稍后创建完成,再请求该字体子集便会成功(HTTP 200)。A 404 is only a concern if you see more than one on the same primer request, as it would indicate an issue with the subset augmentation.
404 错误只有在 primer 请求都相同的情况下仍多次出现时才需要注意,因为这可能表明子集扩增(subset augmentation)存在问题。
实际体验中观察到网络请求:
形如 https://use.typekit.net/af/....../.../../m?unicode={...}&features=ALL&v=3
的请求返回 content-type: font/opentype
形如 https://use.typekit.net/af/....../.../../m?unicode={...}&gdyn={...}&v=3
content-type: application/x-typekit-augmentation
依据 content-type 猜测,前者应该是一个包含大多数常用字的基本字符集,后者应该是实现所谓子集扩增(subset augmentation)而特殊构造的字形封装格式。
其中 gdyn={...}
内容挺长,应该是描述所需要字形(范围)的数据
此外,还有 https://use.typekit.net/af/....../.../../m?primer={...hash?}
,也是返回 content-type: application/x-typekit-augmentation
,结合文档的说法推测应该是与 gdyn={...}
请求有关的哈希缓存实现,避免多个终端客户针对同样页面上同样的字形需求,多次重复发送大量描述数据。
我个人感觉即便应用这项技术,在线中文(亚洲)字体应该也不会流行起来。就我个人感受,我们大多数人心中已经对字体有很深刻的庞大感的印象了,如果一个应用程序或网页使用了什么奇怪的字体(还是大篇大篇中文的),很难不让人觉得它捆绑或下载了很大体积的字体文件(尽管事实上它用了动态按需加载技术),更何况大部分字体在普通像素密度(低 DPI)的 PC 屏幕上的小字呈现效果远差于系统字体。在这种环境下,使用本地字体呈现网页和小型程序界面的主内容基本已经是一种正式和专业的代表、常识般的存在;全页面在线字体往往只有小众的网站才使用,因此给人留下了一种彰显艺术、个性化、轻松的暗示;对于大型正式网站,整版整版地擅自换字体,反而可能容易让人一时间反感;而对于小型站点而言,动态子字集这样的在线字体服务的接入门槛和费用开销很难忽略。
评论
我想这个技术还可以防止用户轻易的把整个字体下载下来。
就比如我刚刚在试着从adobe font的网页下载vdl-gigamarujr。下下来的字体缺很多字,完全没法用,所以我又回去琢磨了以下这个dynamic subsetting的请求和response,啥都看不出来...
@Ynng:确实喔,没想到还有这一层优点
总有许多安卓用户反映网页样式无法正常加载,几经排查最终确定属用户奇葩的系统字体所致,于是不得不引用统一字体以防排版失常˚‧º·(˚ ˃̣̣̥᷄⌓˂̣̣̥᷅ )‧º·˚
发表评论