`

浏览器如何渲染文本

 
阅读更多

浏览器是我们最常用的软件之一,文本又是网页中最主要的元素, 在浏览器显示文本的过程中有许多有趣的细节,值得展开来讲讲,或许能减少一些误解。

这是一个比较粗略的,概括性的介绍,尽可能不涉及过多的技术细节和具体实现,而立足于给 Web 开发者和设计师提供一些正确的概念。

下面的介绍主要根据我对 WebKit 和 Gecko (Firefox) 的印象来谈,其他的浏览器也大致相同,如有阙漏之处欢迎指出。

解码

当浏览器收到来自 Web 服务器的网页数据之后, 第一步是要把它解码成可以阅读的文本,因为历史原因,不同区域和语言的网页可能会使用不同的编码方式,而浏览器判断编码主要是依据以下方法:

  • Web 服务器返回的 HTTP 头中的 Content-Type: text/html; charset= 信息, 这一般有最高的优先级;
  • 网页本身 meta header 中的 Content-Type 信息的 charset 部分, 对于 HTTP 头未指定编码或者本地文件,一般是这么判断;
  • 假如前两条都没有找到,浏览器菜单里一般允许用户强制指定编码;
  • 部分浏览器 (比如 Firefox) 可以选择编码自动检测功能, 使用 基于统计的方法 判断未定编码。

分段

编码确定后,网页就被解码成了 Unicode 字符流,可以进行进一步的处理, 比如 HTML 解析了,不过我们这里跳过 HTML/XML 解析的细节, 单讲得到了解析后的 文本元素 之后该怎么处理。

因为我们得到的文本可能是很多种语言混杂的, 里面可能有中文、有英文,它们可能要用不同的字体显示; 也可能有阿拉伯文、希伯来文这种从右到左书写的文字; 也有可能涉及印度系文字这样涉及复杂布局规则的文字; 另外,还可能有网页内自己指定的文本语言, 比如<span lang="jp">日本语</span> 这样的标记,使得日文汉字可以使用日文字体显示 (因为 Han Unification 导致这些汉字和中文里的汉字使用同样的代码点,尽管很多写法不同), "lang" 属性也可以在 HTTP 头、<meta> 或者 <html> 出现, 用于标记整个文档的全局语言,通常这是一种好的习惯,方便浏览器进行字体匹配。

为了统一处理所有这些复杂的情况,我们要将文本分为由不同语言组成的小段, 在有的文本布局引擎里,这个步骤称为“itemize”, 分解后的文本段常被称作“text run”,但是具体划分的规则可能根据不同的引擎有所区别, 比如 HarfBuzz 和 ICU 一般是根据要使用的不同排版类来划分 (常称作“shaper”), 比如英语和法语可能使用同一个 shaper 排版, 那么相邻的英语和法语文本就会划分到同一个 run 里,而希伯来文需要另一个 shaper, 就划分到它自己的 run 里,以 HarfBuzz 为例,它有这样一些 shaper:

  • 通用的 (适用于中文、英文等等大多数布局规则简单的语言)
  • 阿拉伯文
  • 希伯来文
  • 印度系文字
  • 高棉文
  • 缅文
  • 谚文

不少浏览器还会在这个划分下面,在确定具体使用的字体之后,根据使用字体的不同划分更细的 run, 这种 run 可能称作“SimpleTextRun”,每个都会使用和相邻不同的字体, 最后把它们逐一交给 shaper 进行排版得到要绘制的字形,这样一来, shaper 的工作就被简化为 在确定的语言、确定的字体下排版确定的文本, 生成对应的字形和它们应该放置的位置、占用的空间

下面先详细说说确定字体的步骤。

字体

说到字体,首先必须提到的就是 CSS 里的 font 和 font-family 等规则。

比如这样的规则:

p { font-family: Helvetica, Arial, sans-serif; }
strong { font-weight: bold; }

如果对于这样一段文本:

<p>A quick brown fox <strong>jumps</strong> over the lazy dog.</p>

表示这个段落里优先使用 Helvetica 这个 family 的字体,如果找不到, 就找 Arial,如果还是找不到,就用浏览器设置的默认非衬线字体 (有的浏览器,比如 Safari 只给你一个设置,有的像 Firefox 则允许根据不同语言设置, 这时可以根据前面分析得到的文本 run 语言信息来判断该用哪个), 这个过程非常简单,大家都很好理解。

稍微复杂一点的是“jumps”,它应该继承父元素的 font-family,也用 Helvetica, 但不用默认的 Regular,而用 Bold 版本,假如找不到 Helvetica Bold, 就找 Arial Bold,否则就找浏览器设置的那个字体的 Bold 版本,假如都没有呢? 就要考虑用人工伪造的方式来显示粗体了,这个且按下不谈, 先看对于中文常见的情况:CSS 指定的字体没有覆盖我们需要的文本时,该怎么做。

比如还是上面的 CSS 规则,但对这样的文本:

<p>一只敏捷的狐狸...</p>

这里的“一只敏捷的狐狸”该用什么字体呢? 假设 CSS 里具体指定了中文字体,比如 Helvetica, STHeiti, sans-serif,那很简单, 按照英文字体一样的规则来判断:逐个字符尝试当前的字体是否提供了针对该字符的字形, 如果没有则尝试下一个,要是到了最后都没找到匹配的字体呢?

CSS 规范里只简单的说执行“system font fallback”,但这个过程在不同的浏览器下可能很不一样, 比如 WebKit 会使用 font-family 列表里的第一个字体 和这段文本所属的语言来寻找 fallback 字体, 像 Times 这样的 serif 字体对应的中文 fallback 字体,在 Mac OS X 下是华文宋体 (STSong); 而 Firefox 则会根据 sans-serif 这样的通用 font family 和对应的语言匹配到设置中针对对应语言的默认字体, 比如在 Mac OS X 默认的中文非衬线字体是华文黑体 (STHeiti)。

Linux 下一般通过 fontconfig 去根据语言、风格等参数来选择 fallback,但不同浏览器的实现还可能有区别; Windows 下则一般会使用系统的 Font Linking 机制,根据注册表内的 FontSubstitutes 信息来寻找。

因为在这里不同的浏览器可能有不同的行为,所以建议在 CSS 中写明对应平台该用的字体

具体的字体选择还有一些不太容易注意的细节,也是各个浏览器差异比较大的一点, 可能会出现这样一些问题:

  • 是否支持用字体的 PostScript name 选择:如 STHeiti 的 Light 版本又称作 STXihei, 或者是否能用 full name 选择:有的浏览器不能正确地将 CSS 里对字体的 font-weight 或者 font-style 等要求映射到特定的字体上, 尤其是在字体使用了非标准的 style 命名的情况下,考虑到很多厂商有自己的字体命名规则, 这其实很容易出现,像 Helvetica Neue 的 UltraLight, Light, Regular, Medium, Bold 这些不同的 weight, 是怎么对应到 CSS font-weight 的 100 到 900 数值上的? 这就是特别容易出现 bug 的地方。

  • 是否支持按 localized name 选择:比如能不能用 "宋体" 来代表 "SimSun"。 以 Mac OS X 下的浏览器为例,Firefox 支持这样的写法, 但基于 WebKit 的浏览器一般不支持,这样的问题 CSS 规范没有限定, 所以无论哪种情况都是允许的。

总的说来,如果要保证最大限度的兼容性,在 CSS 书写的时候应该 尽可能选择明确、不容易出错的写法, 尽量少隐式地让浏览器自己确定 (be explict instead of implict), 虽然隐式写法通常比较简洁,但除非你 100% 确定想支持的浏览器在你想支持的平台下都能支持这个写法, 否则还是不应该轻易用。

CSS3 新增的 @font-face 规则则是对于现有规则的扩展,提供了 web fonts 功能,但字体匹配算法的逻辑并没有改变,详细的算法可以看 CSS 规范里的说明。

渲染

当确定了字体以后,就可以将文本、字体等等参数一起交给具体的排版引擎,生成字形和位置, 然后根据不同的平台调用不同的字体 rasterizer 将字形转换成最后显示在屏幕上的图案, 一般浏览器都会选择平台原生的 rasterizer,比如 Mac OS X 下用 Core Graphics, Linux/X11 下用 FreeType,Windows 下用 GDI/DirectWrite 等等。

关于这个步骤,typekit 的这篇 blog 可以作为参考。 各个浏览器的差异主要来自使用的排版引擎可能对不同的语言支持有差异, 调用 rasterizer 使用的参数可能有差异 (比如是否启用 subpixel rendering、 使用的 hinting 级别等等),但在同一个操作系统下的效果差别不会很大。

建议

基于以上的介绍,可以尝试提出一个在现有浏览器下,针对中文用户的,书写 CSS 字体选择规则的建议,如下:

  1. 首先确定要选择字体的元素应该使用的字体风格,比如是衬线字体、非衬线字体还是 cursive、fantasy 之类的;
  2. 确定了风格之后,先选择西文字体,优先把平台独特的、在该平台下效果更好的字体写上,比如 Mac OS X 下有 Helvetica 也有 Arial,但 Helvetica (可能) 效果更好,Windows 下则一般只有 Arial,那么写 Helvetica, Arial 就比 Arial, Helvetica 或者只有 Arial 更好;
  3. 然后列出中文字体,原则相同,多个平台共有的字体应该尽量放在后边,独有的字体放在前面,还需要照顾到 Mac OS X/Linux 下一般用户习惯用(细)黑体作为默认字体,Windows 下习惯以宋体作为默认字体的情况,比如 STXihei, SimSun 这样的写法比较常见,如果写作 SimSun, STXihei,但 Mac OS X 上装了 SimSun 效果就不会太好看。
  4. 最后还是应该放上对应的 generic family,比如 sans-serif 或者 serif。
  5. 尽量用字体的基本名称 (比如 English locale 下显示的),而不要用本地化过的名称。除非特殊情况 (Windows 下“某些”浏览器在特定编码下只能支持本地化的字体名称)。Mac OS X 下字体名称可以用 Font Book 查到 (菜单 Preview -> Show Font Info),Windows 下字体信息在微软的网站可以得到,Linux/X11 下可以使用 fc-list 命令查到。
  6. 字体名称中包含空格时记住用引号扩起,比如 "American Typewritter" 和 "Myriad Pro"。
  7. 文档开头最好指明语言,比如 <html lang="zh-CN">,可以使用的语言标记参见 W3C 的说明。
推荐
18
21
分享到:
评论

相关推荐

    浏览器渲染文本过程分析

    在了解浏览器渲染文本过程之前,我们首先应该对浏览器的基本功能有所认识。浏览器作为一个客户端软件,其主要功能是从远程服务器获取资源,并将这些资源(如HTML、CSS、JavaScript等)按照一定的规则渲染成用户能够...

    深入理解CSS行高line-height与文本垂直居中的原理

    在浏览器渲染文本时,每个段落或行的文本会被包裹在一个无形的框内,称为行框。行框的高度由`line-height`决定,包括上间距、文本本身的高度以及下间距。默认情况下,上间距和下间距相等,使得文本在行框内保持垂直...

    browsh一个完全交互式实时和现代基于文本的浏览器渲染至TTY和浏览器

    1. **文本渲染引擎**:browsh需要一个能够解析和渲染HTML、CSS的引擎,将网页内容转换成适合终端显示的文本。 2. **事件处理**:通过JavaScript或其他方法处理用户的输入,如键盘命令,以模拟图形界面中的鼠标操作...

    selenium进行chrom浏览器渲染.zip

    这个名为“selenium进行chrom浏览器渲染.zip”的压缩包,显然包含了与使用Selenium控制Chrome浏览器相关的资源,包括JDK(Java Development Kit)和使用说明。这里我们将详细探讨Selenium、Chrome浏览器渲染以及如何...

    一个像浏览器或IDE一样缩放自如的文本浏览器.zip

    标题 "一个像浏览器或IDE一样缩放自如的文本浏览器.zip" 暗示了这是一个针对文本查看和编辑的软件,其设计灵感可能来源于常见的浏览器和集成开发环境(IDE)。这个程序具备了一些高级功能,比如使用滚轮进行文本缩放...

    文本浏览器w3m-0.5.3.tar.gz

    在数字化时代,虽然图形用户界面的浏览器已经占据了主导地位,但文本模式的浏览器依然有着其独特的应用场景和价值。w3m,作为一款优秀的文本浏览器,以其简洁、高效的特点,深受程序员和终端爱好者喜爱。本文将对w3m...

    详解浏览器渲染页面过程

    浏览器渲染页面的过程是网页开发中至关重要的一环,它涉及到用户从输入URL到看到完整页面的整个体验。下面我们将深入探讨这个过程的各个阶段,并提供一些优化页面性能的策略。 首先,浏览器接收到HTML文件后开始...

    基于websocket实现浏览器端文本、视频、语音的即时通讯.zip

    在基于WebSocket实现浏览器端文本、视频、语音的即时通讯中,我们可以深入理解以下几个关键知识点: 1. **WebSocket基本原理**:WebSocket协议是HTTP/1.1协议的一个扩展,它通过一次握手建立长连接,解决了HTTP协议...

    文本渲染引擎trmix.zip

    trmix(Type Rendering Mix) 是个基于浏览器的应用 CSS 文本渲染的引擎。Type Rendering Mix 通过解析用户代理字符串检测浏览器的文本 rasterizer 和 antialiasing 方法。 Type Rendering Mix 支持的浏览器: IE6 ,...

    lynx2.8.7 纯文本浏览器

    **lynx2.8.7 纯文本浏览器** Lynx是一款历史悠久且功能强大的纯文本浏览器,它在互联网发展的早期就扮演了重要角色。这款浏览器的主要特点在于它完全不依赖图形用户界面(GUI),而是通过命令行接口进行操作,使得...

    pb做的浏览器模型_浏览器_pb浏览器_

    - **安全增强**:二进制格式的数据相比文本格式更难被篡改,可能提升了浏览器的安全性。 此外,一个自定义的浏览器还可能关注以下几个关键点: - **跨平台支持**:为了适应不同操作系统,如Windows、macOS、Linux...

    手机网页浏览器 Wap浏览器 wml浏览器

    它允许用户通过简单的文本格式WML(Wireless Markup Language)来访问网页内容。WML是专为低带宽、有限显示空间的移动设备设计的标记语言,其设计目标是使网页在小屏幕和有限功能的手机上能够高效显示。 Wap浏览器...

    水星浏览器 v1.01版(P2)

    CEF 是一个开源项目,它允许开发者将谷歌Chrome浏览器的渲染引擎嵌入到自己的应用程序中,使得开发者可以利用最新的Web技术构建桌面应用。在水星浏览器中,这个功能被简化并优化,使其更适合易语言的开发者使用。 ...

    基于QT的浏览器

    `西西软件下载.txt` 可能是一个包含有关如何下载、更新或获取QTWeb浏览器其他版本的文本文件,通常会提供链接、版本信息和使用说明。而`.url` 文件是一种快捷方式文件,类似于Windows操作系统的桌面快捷方式,指向...

    j2me手机浏览器/j2me手机浏览器

    此外,早期的移动互联网服务往往使用WAP(Wireless Application Protocol)协议,因此,这些浏览器也支持WAP1.x和WAP2.0协议,以便在GPRS或EDGE等较慢的网络环境下加载优化过的文本和图片内容。 **用户界面** 由于...

    浏览器

    HTTP(超文本传输协议)和HTTPS(安全版的HTTP)是浏览器与服务器通信的主要协议。此外,TCP/IP(传输控制协议/互联网协议)用于确保数据在网络中的可靠传输,WebSocket提供持久化的双向通信,而FTP(文件传输协议)...

    java 网页浏览器开发

    虽然Java可能不如JavaScript那样直接支持高性能的浏览器渲染,但开发者可以使用JavaFX的Scene Graph或自定义的绘图API来实现基本的渲染功能,如文本渲染、图片加载等。 此外,考虑到安全性,开发者还需要关注Java的...

    C#编写的自制浏览器

    2. **处理用户输入**:在地址栏的文本改变事件中,解析用户的URL输入,然后启动加载过程。 3. **网络请求**:使用HttpWebRequest或HttpClient发送GET请求到指定URL,获取HTML响应。 4. **解析和渲染**:如果使用...

Global site tag (gtag.js) - Google Analytics