百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Web字体应用修炼之道(上)

myzbx 2025-02-13 13:14 33 浏览

故事的起源,要从UED界两大种族前端设计师和视觉设计师的爱恨说起:

设计师的视觉稿:

前端开发出来的真实效果:

于是战争爆发了:

像这种视觉效果不一致问题,在日常开发中比比皆是。最近遇到的比较多的是字体问题,开了写轮眼的设计师经常抱怨手机上的字体跟设计稿不一致,前端只能无奈的回一句手机上没这字体啊...然而实际情况远比这个复杂,正义的王二小见此情况决定挺身而出,踏上了Web字体修真之路,来寻找传说中的最优解。

从0开始

这将是一次冒险,我们从0开始探索网页中的文字是如何一步步呈现在我们眼前的。计算机的数据,本质上都是由01组成的序列,不同的序列可以传达不同的信息,而同样的序列通过不同的编码和解码方式也会传达不同的信息。

我们所看到的网页,都是从服务端网络传输而来的一个个数据包通过浏览器解析而成,网络传输其实是一个很复杂的编码解码过程,你可能听过数据段,报文,分组,数据包,数据帧等关键词,这些术语其实只是OSI模型中各个层对数据单位的不同划分,最底层的表示还是以bit为单位的01。假设浏览器现在要渲染一段文本,它从服务端收到的数据包有一段信息是这样的(当然为了简化,除去报文头等信息,假设下面这段信息就页面上要展示的文本信息):

11100101 10001010 10101000 11100110 10000100 10011111 11100101 10110000 10001111 11100101 10001001 1000110111100111 10101011 10101111

这是一串字节流,浏览器得到它的第一件事自然是解码,那么第一个问题,编码方式很多种,浏览器怎么知道用哪种方式去解码呢?

编码与解码

我们所熟知的编码方式有ASCII,GB2321,UTF-8,UTF-16等等,对于浏览器来说,它会按照以下规则去寻找数据的编码类型:

  • Web 服务器返回的 HTTP 头中的 Content-Type: text/html; charset="xxx"。其中charset="xxx"就是编码方式,当浏览器拿到这个信息之后,就能愉快的解码了;

  • 如果服务端没有指定编码方式,浏览器会去网页文件的head中查找信息,来确定编码方式。

  • 如果还没找到,那浏览器就只能自行判断编码了,或者让用户设置解码方式。

可以看到,前两步信息都是确定的,只有第三步是无法确定编码方式的。所以为了让你的页面能正常展示出来,一定得要在前两步就设定好charset编码方式,以便于浏览器以你期望的方式解码。

现代网页通常都使用utf-8的编码方式,所以我们就以此为例。utf-8是unicode字符集的一种实现方式,unicode本质上就是一个表,一个将二进制数据映射到各种文字符号的表,这个表野心很大,想要囊括世界上所有文字符号,并且他也实现了自己的目标,所以它也成了网络世界应用最广泛的一个表。

假设上面那串字节流采用了utf-8编码,那么根据utf-8字节流到unicode的编码规则:

可以看到上面那段字节流全都是1110xxxx 10xxxxxx 10xxxxxx的形式,那么根据表中第三行映射关系,应该是3个utf-8字节对应1个unicode编码,将三个字节中的16个x用两个字节表示,然后转化成十六进制的unicode表示,最终可得到以下结果:

11100101 10001010 10101000 -> 01010010 10101000 -> \u52a811100110 10000100 10011111 -> 01100001 00011111 -> \u611f11100101 10110000 10001111 -> 01011100 00001111 -> \u5c0f11100101 10001001 10001101 -> 01010010 01001101 -> \u524d11100111 10101011 10101111 -> 01111010 11101111 -> \u7aef

得到unicode编码之后,我们就可以根据unicode字符表找到对应的文字符号,最终得到了以下结果:

\u52a8\u611f\u5c0f\u524d\u7aef -> 动感小前端

如果对最终的结果不确定,可以反向验证一下:

escape('动感小前端') // "
%u52A8%u611F%u5C0F%u524D%u7AEF"

得出的unicode字符数值完全一致,看来计算没错,那么紧接着第二个问题来了,浏览器该如何去展示它?就好比我知道你的名字叫什么,但并不知道怎么写一样。

寻找字体

字体的渲染是一个很复杂的过程,首先我们需要知道在Web世界中存在着五大字体家族,江湖人称font-family:serif、sans-serif、monospace、cursive和fantasy。在这五大家族下面,又演变出各个不同的字体,比如宋体,微软雅黑,Arial,Helvetica等等。同样的文字,在不同的字体下面会呈现出不同的效果:

但是,不管是什么字体,他们本质上都是一个表。你可以把这个表理解成三个部分:

  • 轮廓:用来记载字符的形状;

  • 编码:用来记载字符内部编号与字符形状以及unicode编码之间的映射关系;

  • 封装:将上面这些东西封装成特定的文件格式

想要深入了解字体内部原理,请走支线剧情《Fonts & Encodings》

浏览器在渲染字体时,首先会把这些文字分为不同语言的小段,然后依次确定该用哪一种字体,确定之后按照字符的unicode编码在字体中匹配相应的轮廓,并最终渲染在屏幕上。通常我们都会给页面指定一套字体规则:

font-family: Helvetica, STXihei, "Microsoft YaHei", Arial, SimSun,sans-serif;

浏览器会按照字体声明的顺序依次去寻找系统中已安装的字体,如果找到了就按照该字体渲染,没找到则依次往后查找,如果最后还是没找到,则使用浏览器设置的**神秘的默认字体**。

渲染排版

确定了字体之后,浏览器就真的要去渲染了。如果你以为把字体设置的一样就能万事大吉了,那就太天真了。即使是相同的字体,不同的环境下渲染出来的结果也是不一样的!就好比同样是须佐能乎,不同人产生的形态也是不一样的,先看两张图:

相同字体在不同环境下的效果:

放大后的对比效果:

这是同一个页面在不同环境下的显示效果,其实如果在真实环境下看的话基本看不出来差别,但是对比一看差别还是很明显的。MBP下是retina屏,显示效果更细腻一些,而MBA下则更厚重些。放大来看,MBP下字体边缘有灰色的边缘(灰度渲染),而MBA下则是彩色的边缘(次像素渲染)。

可以看到,同样是Mac系统+Chrome浏览器,只是版本号稍微不同,渲染效果就会有所差别。更别说在Windows和Android上了。那么造成这种差异的原因是什么呢?

排版引擎

不同浏览器有着不同的渲染引擎,不同的操作系统上面也有不同的文字排版引擎,而浏览器在渲染页面文本的时候都会调用系统的文字排版引擎。不同的排版策略就会造成不同的渲染结果。

Mac使用的排版引擎为CoreText,Windows7为DirectWrite/GDI,Windows XP则使用GDI。我们不会深入探索各个排版引擎的原理,只需要知道不同的渲染引擎可能会造成字体有细节上的差异。即使是同一种渲染引擎,采用不同的渲染策略,比如灰度渲染和亚像素渲染,得出的效果也是不一样的。

Core Text 渲染引擎:

DirectWrite渲染引擎:

GDI渲染引擎,开启标准抗锯齿:

GDI渲染引擎,无抗锯齿:

想要深入了解Web字体渲染知识,可以去Typekit上刷支线剧情。

由此可看出排版引擎渲染策略的差异是造成字体显示效果不一致的根本原因之一,但是这种差异非常之小,对于普通用户来说,根本不会注意到这些细节,所以前端工程师大可不必为此操心。

至此,我们终于走完文字从0渲染到屏幕上的整个过程。

诸子百家

之前有提到,当浏览器没有找到所声明的字体时,会使用默认字体。问题就在于,这个默认字体到底是什么字体呢?不同设备之间的默认字体又分别是什么?影响默认字体的因素又有哪些呢?

在旧PC时代,统治人类的主要是windows和mac两大阵营,我们扳着手指头都能列出各大平台和浏览器上的默认字体。但是到了如今的无线乱世,安卓的开源让每个设备厂商都可能会有自己独特的默认字体,这对网页的视觉统一性又带来了巨大的挑战。

裸奔字体

裸奔字体就是你的页面不设置任何样式,浏览器呈现出的默认字体,我写了个小demo,你可以点击试试看你浏览器上面的裸奔字体是啥,也可以扫码看看手机上的情况:

在CrossBrowserTesting上跑了一下效果如下:

Win8/OSX 部分浏览器对比:

Firefox,Safari,Chrome对比:

很明显能看出,裸奔字体千变万化,根本不靠谱!

安全字体

好在,现在已经没有人裸奔了,一般都会在页面中手动声明一下字体,比如百度首页是这样的:

body{font: 12px arial;} // 写的这么精简是为了省流量么...

谷歌首页是这样:

body{font-family: arial,sans-serif;} // 好歹加了字体族

天猫首页是这样的:

body{font: 12px/1.5 tahoma,arial,"\5b8b\4f53";}

淘宝首页是这样的:

body{font: 12px/1.5 tahoma,arial,'Hiragino Sans GB','\5b8b\4f53',sans-serif;}

上面四种写法可能都有自己的考虑,但仅从终端字体表现的角度来看,很明显淘宝的写法更专业。Arial可谓是支持性最广的字体了,所以大家都用上了,这种被大多数系统所默认支持的字体,就是Web安全字体。

CSS Font Stack上有对Web安全字体的整理,建议设计师们在作图的时候多考虑一下,这样能一定程度上降低视觉差异。并且某些字体其实长得还是蛮像的,你还可以使用安全字体来代替长相相似的非安全字体。

到目前为止,我们所做的一切考虑就是让页面字体效果在不同终端下尽可能保持一致,初步结论就是要使用安全字体,然而设计师并不这样想。设计师一般会使用逼格比较高的非安全字体,比如兰亭细黑,苹方字体。一旦浏览器发现系统没有这些字体,就会不断降级,最坏的情况,就是一直降级到默认字体。所以通常我们会在font-family最后加上一个默认的字体族,比如sans-serif,这样浏览器在最坏的情况下也能使用特定的字体族,并在该字体族下选择一名指定字体来展示。

那么在这些指定的种族背后,被选中的孩子们到底都有谁呢?

神秘的默认字体

首先系统会默认安装一些字体,维基上有对Win/Mac内置字体的整理:

  • Windows 字体列表

  • Mac OS X 字体列表

然后当你安装软件时,有可能会附带安装一些字体,这样你系统上能支持的字体又变多了。在上面那份列表中,Win/Mac共同支持的字体只有Arial, Verdana, Tahoma, Trebuchet MS, Georgia等少数Web安全字体,对于Win/Mac平台实际字体效果分析,请参考此文:

跨平台字体效果浅析
:https://isux.tencent.com/5058.html

重点说下无线端, iOS Fonts 和iOS Font List网站整理了一份各个版本的iOS字体清单,可以很方便的查出各版本支持情况:

虽然方便,但毕竟第三方网站,不排除数据有误的情况,于是附上官网声明的字体清单:

  • iOS 5:字体列表

  • iOS 6:字体列表

  • iOS 7:字体列表

  • iOS 8:字体列表

  • iOS 9:字体列表

对于安卓,**原生的安卓**使用的是Droid Sans(英文/数字)和Droidsansfallback(中文),4.0后修改为Google的开源字体Roboto。而非原生安卓,实在没有总结性可言。比如小米和华为用了方正兰亭黑,锤子则使用了华文黑体,并且同一厂商下的不同手机品牌,同一品牌的不同型号默认字体都可能不同,不做展开。

一张图总结一下:

Windows Phone 默认英文字体是Segoe,中文字体在WP8以前是雅黑,WP8之后是方正等线体。

YunOS,貌似是方正兰亭细黑...

强大的自定义字体

是的,用户可以选择自己喜欢的字体。你永远不知道用户会干什么,什么安全字体,默认字体,一个主题包下来全都是浮云:

当然这不是最绝的,换个字体最多样子变了,最绝的是用户开启老人机模式,放大字体!

这两招一出,基本会给设计师和前端造成10000+伤害,不过我们仍然可以做点什么:

  • 严格控制页面布局,字体超出部分截断,保证页面正常显示;

  • 监测页面缩放情况并给予用户提示;

  • 页面自适应或者,针对老人模式单独开发一套页面。

小结

看到这里王二小已经残血,稍微修整总结一下,字体表现不一致的根本原因有:

  • 排版引擎渲染策略差异(影响小,不可规避)

  • 各终端默认字体设置差异(影响中,可规避)

  • 用户手动设置自定义字体(影响大,不可控)

目前为止我们能做的就是尽量使用Web 安全字体,针对不同终端对font-family字体选择顺序进行优雅降级,并设置默认字体族来规避风险。

但只做到这些还远远不够,我们完全处于被动状态,一切都依赖于终端环境的字体情况,并且还没考虑到字体格式,中英混排,字体动画,字体优化,Web标准技术等方面。接下来我们要主动出击,站在巨人的肩膀上去各个击破,打怪升级,去寻找Web字体应用最佳实践之道。

冒险越来越深入了,等待王二小的将会是什么呢?请看下集:

参考资料

以下是相关参考资料,若想深入了解,建议仔细研读。

Web 字体的选择和运用

https://blog.coding.net/blog/Web-Fonts

网页字体优化

https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization?hl=zh-cn

字体的各个概念术语

http://www.zhihu.com/question/20366900

字体渲染相关

  • http://ued.ctrip.com/blog/font-rendering.html

  • http://blog.jobbole.com/21671/

  • http://isux.tencent.com/website-font-rendering-process.html

  • https://developer.apple.com/fonts/TrueType-Reference-Manual/RM02/Chap2.html

Typekit Web字体渲染系列文章

  • http://blog.typekit.com/2010/10/05/type-rendering-on-the-web/

  • http://blog.typekit.com/2010/10/15/type-rendering-operating-systems/

  • http://blog.typekit.com/2010/10/21/type-rendering-web-browsers/

  • http://blog.typekit.com/2010/11/09/type-rendering-the-design-of-fonts-for-the-web/

  • http://blog.typekit.com/2010/12/08/type-rendering-font-outlines-and-file-formats/

  • http://blog.typekit.com/2010/12/14/a-closer-look-at-truetype-hinting/

  • http://blog.typekit.com/2010/12/17/type-rendering-review-and-fonts-that-render-well/

网页设计中默认字体详解

https://waxdoll.gitbooks.io/webdesignfoundations/content/appendix/font_browser_default.html

Mac OS X 字体列表

https://en.wikipedia.org/wiki/List_of_typefaces_included_with_OS_X

Windows 字体列表

  • https://en.wikipedia.org/wiki/List_of_typefaces_included_with_Microsoft_Windows

  • http://www.microsoft.com/typography/fonts/product.aspx

开源字体列表

https://en.wikipedia.org/wiki/Open-source_Unicode_typefaces

CSS Font Stack

http://www.cssfontstack.com/

数字设计之美

http://www.typeisbeautiful.com/2009/09/1467/

跨平台字体效果浅析

https://isux.tencent.com/5058.html

对比 iOS 系统 Android 的字体渲染有何区别

https://www.zhihu.com/question/21211748

iOS Font 字体整理

  • http://iosfonts.com/

  • http://iosfontlist.com/

Mars/font-family

https://github.com/AlloyTeam/Mars/blob/master/solutions/font-family.md

网页字体设置你了解吗?

http://ued.ctrip.com/blog/web-page-font-settings-did-you-know.html

更多深度技术内容,请关注云栖社区微信公众号:yunqiinsight。

相关推荐

如何设计一个优秀的电子商务产品详情页

加入人人都是产品经理【起点学院】产品经理实战训练营,BAT产品总监手把手带你学产品电子商务网站的产品详情页面无疑是设计师和开发人员关注的最重要的网页之一。产品详情页面是客户作出“加入购物车”决定的页面...

怎么在JS中使用Ajax进行异步请求?

大家好,今天我来分享一项JavaScript的实战技巧,即如何在JS中使用Ajax进行异步请求,让你的网页速度瞬间提升。Ajax是一种在不刷新整个网页的情况下与服务器进行数据交互的技术,可以实现异步加...

中小企业如何组建,管理团队_中小企业应当如何开展组织结构设计变革

前言写了太多关于产品的东西觉得应该换换口味.从码农到架构师,从前端到平面再到UI、UE,最后走向了产品这条不归路,其实以前一直再给你们讲.产品经理跟项目经理区别没有特别大,两个岗位之间有很...

前端监控 SDK 开发分享_前端监控系统 开源

一、前言随着前端的发展和被重视,慢慢的行业内对于前端监控系统的重视程度也在增加。这里不对为什么需要监控再做解释。那我们先直接说说需求。对于中小型公司来说,可以直接使用三方的监控,比如自己搭建一套免费的...

Ajax 会被 fetch 取代吗?Axios 怎么办?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!今天给大家带来的主题是ajax、fetch...

前端面试题《AJAX》_前端面试ajax考点汇总

1.什么是ajax?ajax作用是什么?AJAX=异步JavaScript和XML。AJAX是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX可以使网页实...

Ajax 详细介绍_ajax

1、ajax是什么?asynchronousjavascriptandxml:异步的javascript和xml。ajax是用来改善用户体验的一种技术,其本质是利用浏览器内置的一个特殊的...

6款可替代dreamweaver的工具_替代powerdesigner的工具

dreamweaver对一个web前端工作者来说,再熟悉不过了,像我07年接触web前端开发就是用的dreamweaver,一直用到现在,身边的朋友有跟我推荐过各种更好用的可替代dreamweaver...

我敢保证,全网没有再比这更详细的Java知识点总结了,送你啊

接下来你看到的将是全网最详细的Java知识点总结,全文分为三大部分:Java基础、Java框架、Java+云数据小编将为大家仔细讲解每大部分里面的详细知识点,别眨眼,从小白到大佬、零基础到精通,你绝...

福斯《死侍》发布新剧照 "小贱贱"韦德被改造前造型曝光

时光网讯福斯出品的科幻片《死侍》今天发布新剧照,其中一张是较为罕见的死侍在被改造之前的剧照,其余两张剧照都是死侍在执行任务中的状态。据外媒推测,片方此时发布剧照,预计是为了给不久之后影片发布首款正式预...

2021年超详细的java学习路线总结—纯干货分享

本文整理了java开发的学习路线和相关的学习资源,非常适合零基础入门java的同学,希望大家在学习的时候,能够节省时间。纯干货,良心推荐!第一阶段:Java基础重点知识点:数据类型、核心语法、面向对象...

不用海淘,真黑五来到你身边:亚马逊15件热卖爆款推荐!

Fujifilm富士instaxMini8小黄人拍立得相机(黄色/蓝色)扫二维码进入购物页面黑五是入手一个轻巧可爱的拍立得相机的好时机,此款是mini8的小黄人特别版,除了颜色涂装成小黄人...

2025 年 Python 爬虫四大前沿技术:从异步到 AI

作为互联网大厂的后端Python爬虫开发,你是否也曾遇到过这些痛点:面对海量目标URL,单线程爬虫爬取一周还没完成任务;动态渲染的SPA页面,requests库返回的全是空白代码;好不容易...

最贱超级英雄《死侍》来了!_死侍超燃

死侍Deadpool(2016)导演:蒂姆·米勒编剧:略特·里斯/保罗·沃尼克主演:瑞恩·雷诺兹/莫蕾娜·巴卡林/吉娜·卡拉诺/艾德·斯克林/T·J·米勒类型:动作/...

停止javascript的ajax请求,取消axios请求,取消reactfetch请求

一、Ajax原生里可以通过XMLHttpRequest对象上的abort方法来中断ajax。注意abort方法不能阻止向服务器发送请求,只能停止当前ajax请求。停止javascript的ajax请求...