1. 简介
CSS 允许作者通过 @font-face 规则从网络加载自定义字体。虽然在编写样式表时这很容易使用,但通过脚本动态使用却困难得多。
此外,CSS 允许用户代理选择实际加载字体的时间;如果页面上目前没有任何内容使用该字体,大多数用户代理将不会下载其关联文件。这意味着随后使用该字体时,用户代理在最终察觉到使用并开始下载和解析字体文件时会产生延迟。
本规范定义了 CSS 中字体显示(font faces)的脚本接口,允许轻松创建字体显示(通过 FontFace 接口)并从脚本加载它们(通过 document.fonts)。它还提供了跟踪单个字体或整个页面所有字体加载状态的方法。
本规范中的几处内容使用普通的 ES 对象来定义行为,例如在内部使用 Promise,以及 FontFaceSet 内部使用 Set。我认为这里的意图是这些对象(及其原型链)是原始的,不受作者所做的任何操作的影响。这是一个好的意图吗?如果是,我应该如何在规范中指明这一点?
1.1. 值
本规范使用 Promise,它们定义在 ECMAScript 6 中。MDN 提供了一些 介绍 Promise 的优秀教程资料。
1.2. 任务源
每当本规范将任务排入队列时,它都会将其排入“字体加载”(font loading)任务源。
2. FontFace 接口
FontFace 接口代表单个可用的字体显示。CSS @font-face 规则隐式定义了 FontFace 对象,或者也可以通过 URL 或二进制数据手动构造它们。
typedef (ArrayBuffer or ArrayBufferView );BinaryData dictionary {FontFaceDescriptors CSSOMString = "normal";style CSSOMString = "normal";weight CSSOMString = "normal";stretch CSSOMString = "U+0-10FFFF";unicodeRange CSSOMString = "normal";variant CSSOMString = "normal";featureSettings CSSOMString = "normal";variationSettings CSSOMString = "auto";display CSSOMString = "normal";ascentOverride CSSOMString = "normal";descentOverride CSSOMString = "normal"; };lineGapOverride enum {FontFaceLoadStatus ,"unloaded" ,"loading" ,"loaded" }; ["error" Exposed =(Window ,Worker )]interface {FontFace constructor (CSSOMString , (family CSSOMString or BinaryData ),source optional FontFaceDescriptors = {});descriptors attribute CSSOMString family ;attribute CSSOMString style ;attribute CSSOMString weight ;attribute CSSOMString stretch ;attribute CSSOMString unicodeRange ;attribute CSSOMString variant ;attribute CSSOMString featureSettings ;attribute CSSOMString variationSettings ;attribute CSSOMString display ;attribute CSSOMString ascentOverride ;attribute CSSOMString descentOverride ;attribute CSSOMString lineGapOverride ;readonly attribute FontFaceLoadStatus status ;Promise <FontFace >load ();readonly attribute Promise <FontFace >loaded ; };
澄清所有提到的“文档”(the document),明确引用的是哪个文档,因为对象可以在文档之间移动。
family,类型为 CSSOMStringstyle,类型为 CSSOMStringweight,类型为 CSSOMStringstretch,类型为 CSSOMStringunicodeRange,类型为 CSSOMString-
这些属性都代表了字体显示的对应方面,如 CSS @font-face 规则中定义的描述符所定义。它们的解析方式与相应的 @font-face 描述符相同。它们被字体匹配算法使用,除此之外没有其他影响。
例如,
FontFace的style为"italic",这代表一个斜体字体显示;它并不会让该字体显示变为斜体。获取时,返回与此属性关联的字符串。
设置时,根据相应 @font-face 描述符的语法 解析 字符串。如果与语法不匹配,则抛出
SyntaxError;否则,将该属性设置为解析值的序列化结果。 variant,类型为 CSSOMStringfeatureSettings,类型为 CSSOMStringvariationSettings,类型为 CSSOMStringdisplay,类型为 CSSOMStringascentOverride,类型为 CSSOMStringdescentOverride,类型为 CSSOMStringlineGapOverride,类型为 CSSOMString-
这些属性具有与 CSS @font-face 规则中相应描述符相同的含义,解析方式也相同。
它们会开启或关闭支持该特性的字体中的特定特性。与前面的属性不同,这些属性实际上会影响字体显示。
获取时,返回与此属性关联的字符串。
设置时,根据相应 @font-face 描述符的语法 解析 字符串。如果与语法不匹配,则抛出
SyntaxError;否则,将该属性设置为解析值的序列化结果。 status,类型为 FontFaceLoadStatus,只读-
此属性反映了字体显示的当前状态。对于新创建的
FontFace,它必须是 "unloaded"(未加载)。由于作者明确请求加载字体显示(例如通过
FontFace上的load()方法),或者由于用户代理检测到需要该字体来绘制屏幕上的某些文本,其状态可能会发生隐式改变。 loaded,类型为 Promise<FontFace>,只读-
此属性反映了字体显示的
[[FontStatusPromise]]。
所有 FontFace 对象都包含一个内部 [[FontStatusPromise]] 插槽,用于跟踪字体的状态。它起初处于挂起状态,当字体被成功加载和解析,或发生错误时,它会履行(fulfilled)或拒绝(rejected)。
所有 FontFace 对象还包含内部 [[Urls]] 和 [[Data]] 插槽,其中一个为 null,另一个不为 null(非 null 的那个由构造函数根据传入的数据设置)。
2.1. 构造函数
FontFace 可以从指向字体文件的 URL 构建,或者从包含字体二进制表示的 ArrayBuffer(或 ArrayBufferView)构建。
当调用 FontFace(family, source, descriptors) 方法时,执行以下步骤
-
令 font face 为一个新的
FontFace对象。设置 font face 的status属性为"unloaded",设置其内部[[FontStatusPromise]]插槽为一个新的挂起Promise对象。根据 CSS @font-face 规则相应描述符的语法,解析
family参数和descriptors参数的成员。如果source参数是CSSOMString,则根据 @font-face 规则的 CSS src 描述符语法解析它。如果其中任何一个解析不正确,则用名为 "SyntaxError" 的 DOMException 拒绝 font face 的[[FontStatusPromise]],将 font face 的对应属性设置为空字符串,并将 font face 的status属性设置为 "error"。否则,将 font face 的对应属性设置为解析值的序列化结果。注意: 注意这意味着将纯 URL 作为 source 参数传递(例如
"http://example.com/myFont.woff")是无效的——它至少需要包装在 url() 函数中,例如"url(http://example.com/myFont.woff)"。作为这种不便的补偿,您可以指定多个回退方案、指定每个回退方案的字体类型,并轻松引用本地字体。需要定义基本 URL,以便解析相对 URL。它应该是文档的 URL 吗?这对 Worker 也是正确的吗,还是应该使用它们的 Worker URL?那总是定义的吗?
返回 font face。如果 font face 的
status为 "error",则终止此算法;否则,异步完成其余步骤。 -
如果
source参数是CSSOMString,则将 font face 的内部[[Urls]]插槽设置为该字符串。如果
source参数是BinaryData,则将 font face 的内部[[Data]]插槽设置为传入的参数。 -
如果 font face 的
[[Data]]插槽不为null,则将一个任务排入队列以同步运行以下步骤-
将 font face 的
status属性设置为 "loading"。 -
对于 font face 所在的每个
FontFaceSet-
如果
FontFaceSet的[[LoadingFonts]]列表为空,则 将 FontFaceSet 切换为加载状态。 -
将 font face 追加到
FontFaceSet的[[LoadingFonts]]列表中。
-
异步尝试将内部数据解析为字体。完成后(无论成功与否),将一个任务排入队列以同步运行以下步骤
-
如果加载成功,font face 现在代表已解析的字体;履行(fulfill)font face 的
[[FontStatusPromise]]并返回 font face,并将其status属性设置为 "loaded"。对于 font face 所在的每个
FontFaceSet-
将 font face 添加到
FontFaceSet的[[LoadedFonts]]列表中。 -
从
FontFaceSet的[[LoadingFonts]]列表中删除 font face。如果 font 是该列表中的最后一项(因此列表现在为空),则 将 FontFaceSet 切换为已加载状态。
-
-
否则,用名为 "SyntaxError" 的 DOMException 拒绝 font face 的
[[FontStatusPromise]],并将 font face 的status属性设置为 "error"。对于 font face 所在的每个
FontFaceSet-
将 font face 添加到
FontFaceSet的[[FailedFonts]]列表中。 -
从
FontFaceSet的[[LoadingFonts]]列表中删除 font face。如果 font 是该列表中的最后一项(因此列表现在为空),则 将 FontFaceSet 切换为已加载状态。
-
-
注意: 新构造的 FontFace 对象不会自动添加到与文档或 Worker 线程上下文关联的 FontFaceSet 中。这意味着虽然新构造的字体可以预加载,但它们必须显式添加到 FontFaceSet 之后才能实际使用。请参阅下一节以获取对 FontFaceSet 的更完整描述。
2.2. load() 方法
FontFace 的 load() 方法强制基于 URL 的字体显示请求其字体数据并进行加载。对于从二进制数据构建的字体,或者已经处于加载中或已加载状态的字体,它不执行任何操作。
当调用 load() 方法时,执行这些步骤
- 令 font face 为调用此方法的
FontFace对象。 - 如果 font face 的
[[Urls]]插槽为null,或者其status属性不是"unloaded",则返回 font face 的[[FontStatusPromise]]并中止这些步骤。 - 否则,将 font face 的
status属性设置为 "loading",返回 font face 的[[FontStatusPromise]],并异步继续执行此算法的其余部分。 - 使用 font face 的
[[Urls]]插槽的值,尝试加载字体,如同该值是 @font-face 规则的 src 描述符的值一样,定义见 [CSS-FONTS-3]。 - 当加载操作完成时(无论成功与否),将一个任务排入队列以同步运行以下步骤
- 如果加载尝试失败,用名为 "NetworkError" 的 DOMException 拒绝 font face 的
[[FontStatusPromise]],并将 font face 的status属性设置为 "error"。对于 font face 所在的每个
FontFaceSet-
将 font face 添加到
FontFaceSet的[[FailedFonts]]列表中。 -
从
FontFaceSet的[[LoadingFonts]]列表中删除 font face。如果 font 是该列表中的最后一项(因此列表现在为空),则 将 FontFaceSet 切换为已加载状态。
-
- 否则,font face 现在代表已加载的字体;履行(fulfill)font face 的
[[FontStatusPromise]]并返回 font face,并将其status属性设置为 "loaded"。对于 font face 所在的每个
FontFaceSet-
将 font face 添加到
FontFaceSet的[[LoadedFonts]]列表中。 -
从
FontFaceSet的[[LoadingFonts]]列表中删除 font face。如果 font 是该列表中的最后一项(因此列表现在为空),则 将 FontFaceSet 切换为已加载状态。
-
- 如果加载尝试失败,用名为 "NetworkError" 的 DOMException 拒绝 font face 的
用户代理可以自行发起字体加载,只要它们确定某种给定的字体对于渲染页面上的某些内容是必要的。发生这种情况时,它们必须表现得就像调用了此处描述的相应 FontFace 的 load() 方法一样。
注意: 一些 UA 使用“字体缓存”,避免在页面上或同一源下的多个页面上多次下载同一个字体。多个 FontFace 对象可以映射到字体缓存中的同一个条目,这意味着即使 FontFace 对象不在 FontFaceSet 中,它也可能意外开始加载,因为指向同一字体数据的其他 FontFace 对象(可能在完全不同的页面上!)已经被加载了。
2.3. 与 CSS 的 @font-face 规则的交互
CSS @font-face 规则会自动定义相应的 FontFace 对象,该对象在规则被解析时会自动放置在文档的 字体源 中。此 FontFace 对象是 CSS 连接的。
对应于 @font-face 规则的 FontFace 对象将其 family、style、weight、stretch、unicodeRange、variant 和 featureSettings 属性设置为与 @font-face 规则中相应的描述符相同的值。两者之间存在双向连接:对 @font-face 描述符所做的任何更改都会立即反映在相应的 FontFace 属性中,反之亦然。
当 FontFace 在文档之间转移时,它就不再是 CSS 连接的了。
FontFace 对象的内部 [[Urls]] 插槽被设置为 @font-face 规则的 src 描述符的值,并反映对 src 描述符所做的任何更改。
否则,由 CSS @font-face 规则创建的 FontFace 对象与手动创建的对象相同。
如果从文档中删除了 @font-face 规则,其对应的 FontFace 对象将不再是 CSS 连接的。这种连接无法以任何方式恢复(但将 @font-face 加回到样式表中将创建一个全新的、是 CSS 连接的 FontFace 对象)。
如果 @font-face 规则的 src 描述符更改为新值,则原始连接的 FontFace 对象必须停止成为 CSS 连接的。必须创建一个反映其新 src 的新 FontFace,并将其 CSS 连接到 @font-face。(这也将从它们出现的任何 字体源 中删除旧的 FontFace 对象并添加新的。)
2.4. 发现关于字体的信息
FontFace 对象包括关于字体文件内容的各种只读信息。
[Exposed =(Window ,Worker )]interface { /* The CSSWG is still discussing what goes in here */ }; [FontFaceFeatures Exposed =(Window ,Worker )]interface {FontFaceVariationAxis readonly attribute DOMString ;name readonly attribute DOMString ;axisTag readonly attribute double ;minimumValue readonly attribute double ;maximumValue readonly attribute double ; }; [defaultValue Exposed =(Window ,Worker )]interface {FontFaceVariations readonly setlike <FontFaceVariationAxis >; }; [Exposed =(Window ,Worker )]interface {FontFacePalette iterable <DOMString >;readonly attribute unsigned long ;length getter DOMString (unsigned long );index readonly attribute boolean ;usableWithLightBackground readonly attribute boolean ; }; [usableWithDarkBackground Exposed =(Window ,Worker )]interface {FontFacePalettes iterable <FontFacePalette >;readonly attribute unsigned long ;length getter FontFacePalette (unsigned long ); };index partial interface FontFace {readonly attribute FontFaceFeatures ;features readonly attribute FontFaceVariations ;variations readonly attribute FontFacePalettes ; };palettes
注意: 此只读数据旨在帮助作者了解 font-feature-settings、font-variation-settings 和 @font-palette-values 接受哪些值。
3. FontFaceSet 接口
dictionary :FontFaceSetLoadEventInit EventInit {sequence <FontFace >= []; }; [fontfaces Exposed =(Window ,Worker )]interface :FontFaceSetLoadEvent Event {(constructor CSSOMString ,type optional FontFaceSetLoadEventInit = {}); [eventInitDict SameObject ]readonly attribute FrozenArray <FontFace >; };fontfaces enum {FontFaceSetLoadStatus ,"loading" }; ["loaded" Exposed =(Window ,Worker )]interface :FontFaceSet EventTarget {constructor (sequence <FontFace >);initialFaces setlike <FontFace >;FontFaceSet add (FontFace );font boolean delete (FontFace );font undefined clear (); // events for when loading state changesattribute EventHandler ;onloading attribute EventHandler ;onloadingdone attribute EventHandler ; // check and start loads if appropriate // and fulfill promise when all loads completeonloadingerror Promise <sequence <FontFace >>load (CSSOMString font ,optional CSSOMString text = " "); // return whether all fonts in the fontlist are loaded // (does not initiate load if not available)boolean check (CSSOMString font ,optional CSSOMString text = " "); // async notification that font loading and layout operations are donereadonly attribute Promise <FontFaceSet >ready ; // loading state, "loading" while one or more fonts loading, "loaded" otherwisereadonly attribute FontFaceSetLoadStatus ; };status
ready,类型为 Promise<FontFaceSet>,只读-
此属性反映了
FontFaceSet的[[ReadyPromise]]插槽。有关此
Promise及其使用的更多详细信息,请参阅 § 3.4 ready 属性。 FontFaceSet(initialFaces)-
FontFaceSet构造函数在被调用时,必须迭代其initialFaces参数,并将每个值添加到其 设置条目(set entries)中。 - 迭代顺序
-
迭代时,所有 CSS 连接的
FontFace对象必须排在前面,按其连接的 @font-face 规则的文档顺序排列,随后是非 CSS 连接的FontFace对象,按插入顺序排列。 - set entries (设置条目)
-
如果
FontFaceSet是一个 字体源,则其 设置条目 如 § 4.2 与 CSS @font-face 规则的交互 中指定的那样进行初始化。否则,其 设置条目 最初为空。
add(font)-
当调用
add()方法时,执行以下步骤-
如果 font 已经在
FontFaceSet的 设置条目 中,则立即跳到本算法的最后一步。 -
如果 font 是 CSS 连接的,则抛出
InvalidModificationError异常并立即退出本算法。 -
将 font 参数添加到
FontFaceSet的 设置条目 中。 -
如果 font 的
status属性为 "loading"-
如果
FontFaceSet的[[LoadingFonts]]列表为空,则 将 FontFaceSet 切换为加载状态。 -
将 font 追加到
FontFaceSet的[[LoadingFonts]]列表中。
-
-
返回
FontFaceSet。
-
delete(font)-
当调用
delete()方法时,执行以下步骤-
如果 font 是 CSS 连接的,则返回
并立即退出本算法。false -
令 deleted 为从
FontFaceSet的 设置条目 中删除 font 的结果。 -
如果 font 存在于
FontFaceSet的[[LoadedFonts]]或[[FailedFonts]]列表中,则删除它。 -
如果 font 存在于
FontFaceSet的[[LoadingFonts]]列表中,则删除它。如果 font 是该列表中的最后一项(因此列表现在为空),则 将 FontFaceSet 切换为已加载状态。 -
返回 deleted。
-
clear()-
当调用
clear()方法时,执行以下步骤-
从
FontFaceSet的 设置条目、其[[LoadedFonts]]列表及其[[FailedFonts]]列表中删除所有非 CSS 连接的 项目。 -
如果
FontFaceSet的[[LoadingFonts]]列表非空,则从中删除所有项目,然后 将 FontFaceSet 切换为已加载状态。
-
FontFaceSet 对象还具有内部 [[LoadingFonts]]、[[LoadedFonts]] 和 [[FailedFonts]] 插槽,它们都初始化为空列表,以及一个 [[ReadyPromise]] 插槽,初始化为一个新的挂起 Promise。
因为字体系列仅在使用时才会加载,所以内容有时需要了解字体何时发生加载。作者可以使用此处定义的事件和方法,对依赖于特定字体可用性的操作进行更细致的控制。
如果满足以下任一条件,FontFaceSet 即为 挂起于环境(pending on the environment)
-
文档仍在加载
-
文档有挂起的样式表请求
-
文档有挂起的布局操作,这可能导致用户代理请求字体,或者依赖于最近加载的字体
注意: 其构想是,一旦 FontFaceSet 不再 挂起于环境,只要没有进一步的因素改变文档,作者在进行测量时就可以依赖事物的大小/位置是“正确”的。如果上述条件未能完全涵盖此保证,则需要对其进行修正。
3.1. 事件
字体加载事件使得响应整个文档的字体加载行为变得容易,而无需专门监听每个字体。loading 事件在文档开始加载字体时触发,而 loadingdone 和 loadingerror 事件在文档完成字体加载时触发,分别包含成功加载或未能加载的字体。
以下是 `FontFaceSet` 对象作为 IDL 属性必须支持的事件处理程序(及其对应的事件处理程序事件类型)
| 事件处理器 | 事件处理器事件类型 |
|---|---|
onloading
| loading
|
onloadingdone
| loadingdone
|
onloadingerror
| loadingerror
|
要在 FontFaceSet target 上 触发字体加载事件(名为 e,带有可选的 font faces)意味着使用 FontFaceSetLoadEvent 接口 触发一个名为 e 的简单事件,该接口也满足以下条件
当被要求针对给定的 FontFaceSet 将 FontFaceSet 切换为加载状态 时,用户代理必须运行以下步骤
- 令 font face set 为给定的
FontFaceSet。 - 将 font face set 的
status属性设置为 "loading"。 - 如果 font face set 的
[[ReadyPromise]]插槽当前持有一个已履行(fulfilled)的 Promise,则用一个新的挂起 Promise 替换它。 - 将一个任务排入队列,以在 font face set 上 触发字体加载事件(名为
loading)。
当被要求针对给定的 FontFaceSet 将 FontFaceSet 切换为已加载状态 时,用户代理必须运行以下步骤
-
令 font face set 为给定的
FontFaceSet。 -
如果 font face set 挂起于环境,则将其标记为 卡在环境上(stuck on the environment),并退出本算法。
-
将 font face set 的
status属性设置为 "loaded"。 -
履行(fulfill)font face set 的
[[ReadyPromise]]属性的值,并返回 font face set。 -
将一个任务排入队列以同步执行以下步骤
-
令 loaded fonts 为 font face set 的
[[LoadedFonts]]插槽的内容(可能为空)。 -
令 failed fonts 为 font face set 的
[[FailedFonts]]插槽的内容(可能为空)。 -
将
[[LoadedFonts]]和[[FailedFonts]]插槽重置为空列表。 -
在 font face set 上 触发字体加载事件(名为
loadingdone,带有 loaded fonts)。 -
如果 font face set 的 failed fonts 非空,则在 font face set 上 触发字体加载事件(名为
loadingerror,带有 failed fonts)。
-
每当 FontFaceSet 从 挂起于环境 变为 不 挂起于环境 时,用户代理必须运行以下步骤
-
如果
FontFaceSet是 卡在环境上 且其[[LoadingFonts]]列表为空,则 将 FontFaceSet 切换为已加载状态。 -
如果
FontFaceSet是 卡在环境上,则取消该标记。
若被要求从 FontFaceSet source 查找匹配的字体显示,针对给定的字体字符串 font(可选包含样本文本 text,以及可选的 allow system fonts 标志),运行以下步骤
- 使用 font 属性的 CSS 值语法解析 font。如果发生语法错误,则返回语法错误。
如果解析出的值是 CSS 宽关键词,则返回语法错误。
根据相应属性的初始值绝对化所有相对长度。(例如,像 bolder 这样的相对字体粗细是根据初始值 normal 进行评估的。)
- 如果未显式提供 text,则令其为包含单个空格字符(U+0020 SPACE)的字符串。
- 令 font family list 为从 font 解析出的字体系列列表,font style 为从 font 解析出的其他字体样式属性。
- 令 available font faces 为 source 内的 可用字体显示。如果指定了 allow system fonts 标志,则将所有系统字体添加到 available font faces 中。
- 令 matched font faces 最初为空列表。
- 对于 font family list 中的每个系列,使用字体匹配规则从 available font faces 中选择匹配 font style 的字体显示,并将它们添加到 matched font faces 中。
unicodeRange属性的使用意味着这可能不仅仅是单个字体显示。 - 如果 matched font faces 为空,则将 found faces 标志设置为 false。否则,将其设置为 true。
- 对于 matched font faces 中的每个字体显示,如果其定义的 unicode-range 不包含 text 中至少一个字符的码点,则将其从列表中删除。
注意: 因此,如果 text 为空字符串,每个字体都将被删除。
- 返回 matched font faces 和 found faces 标志。
3.2. load() 方法
FontFaceSet 的 load() 方法将确定给定字体列表中的所有字体是否已加载并可用。如果任何字体是可下载字体且尚未加载,用户代理将发起对这些字体的加载。它返回一个 Promise,当所有字体加载并准备好使用时履行,如果任何字体未能正确加载则拒绝。
当调用 load( font,text ) 方法时,执行这些步骤
- 令 font face set 为调用此方法的
FontFaceSet对象。令 promise 为一个新创建的 Promise 对象。 - 返回 promise。异步完成这些步骤的其余部分。
- 使用传递给该函数的
font和text参数从 font face set 查找匹配的字体显示,令 font face list 为返回值(忽略 found faces 标志)。如果返回语法错误,则用 SyntaxError 异常拒绝 promise 并终止这些步骤。 - 将一个任务排入队列以同步运行以下步骤
- 对于 font face list 中的所有字体显示,调用它们的
load()方法。 - 以等待 font face list 中每个字体显示的
[[FontStatusPromise]]按顺序完成的结果来解析 promise。
- 对于 font face list 中的所有字体显示,调用它们的
3.3. check() 方法
FontFaceSet 的 check() 方法将确定您是否可以“安全地”用特定的字体列表渲染提供的某些文本,从而确保它以后不会导致“字体交换”(font swap)。如果给定的文本/字体组合在渲染时不会尝试使用任何未加载或正在加载的字体,则此方法返回 true;否则返回 false。
-
如果指定的字体存在,但由于其 unicode-range 不覆盖所提供的文本而排除了所有可能的显示,该方法返回
true,因为文本将使用 UA 的回退字体进行渲染,而不会触发任何字体加载。 -
同样,如果指定的字体都不存在(例如名称拼写错误),该方法也返回
true,因为使用此字体列表不会触发任何加载;相反,会发生回退。
当调用 check( font,text) 方法时,执行这些步骤
- 令 font face set 为调用此方法的
FontFaceSet对象。 - 从 font face set 查找匹配的字体显示,使用传递给该函数的
font和text参数,并包含系统字体;令 font face list 为返回的字体显示列表,found faces 为返回的 found faces 标志。如果返回语法错误,则抛出 SyntaxError 异常并终止这些步骤。 - 如果 font face list 为空,或者 font face list 中的所有字体要么具有 "loaded" 的
status属性,要么是系统字体,则返回true。否则返回false。
3.4. ready 属性
因为加载的字体数量取决于为给定文本片段使用了多少字体,在某些情况下,可能不知道是否需要加载字体。ready 属性包含一个 Promise,它在文档完成加载字体时解析,这为作者提供了一种方法,无需跟踪哪些字体已加载或未加载,即可检查可能受字体加载影响的内容。
注意: 作者应注意,给定的 ready promise 只会履行一次,但在它履行后可能会加载更多字体。这类似于监听 loadingdone 事件的触发,但传递给 ready promise 的回调将始终被调用,即使因为相关字体已加载而未发生字体加载时也是如此。这是一种简单、轻松的方法来同步代码与字体加载,而无需跟踪需要哪些字体以及它们具体何时加载。
注意: 注意用户代理可能需要在 ready promise 履行之前迭代多次字体加载。这种情况可能发生在字体回退的情况下,即字体列表中的一个字体已加载但不包含特定字形,而字体列表中的其他字体需要被加载。只有在布局操作完成且无需额外字体加载后,ready promise 才会履行。
注意: 注意此 ready 属性返回的 Promise 只会被履行,永远不会被拒绝,这与 FontFace load() 方法返回的 Promise 不同。
3.5. 与 CSS 字体加载和匹配的交互
当用户代理自动运行 [CSS-FONTS-3] 中的字体匹配算法时,它匹配的字体显示集合必须精确地是文档的 字体源 中的字体集合,加上任何本地字体显示。
当用户代理需要加载字体显示时,它必须通过调用相应 FontFace 对象的 load() 方法来实现。
(这意味着它必须运行相同的算法,而不是字面上调用对象 `load` 属性中当前存储的值。)
FontFaceSet 时可用。向样式表添加新的 @font-face 规则也会将新的 FontFace 添加到 Document 对象的 FontFaceSet 中。添加新的 @font-face 规则
document. styleSheets[ 0 ]. insertRule( "@font-face { font-family: newfont; src: url(newfont.woff); }" , 0 ); document. body. style. fontFamily= "newfont, serif" ;
构造一个新的 FontFace 对象并将其添加到 document
var f= new FontFace( "newfont" , "url(newfont.woff)" ); document. fonts. add( f); document. body. style. fontFamily= "newfont, serif" ;
在这两种情况下,字体资源“newfont.woff”的加载都将由布局引擎发起,就像加载其他 @font-face 规则字体一样。
忽略添加到 document 意味着字体将永远不会被加载,文本将以默认 serif 字体显示
var f= new FontFace( "newfont" , "url(newtest.woff)" , {}); /* new {{FontFace}} not added to {{FontFaceSet}}, so the 'font-family' property can’t see it, and serif will be used instead */ document. body. style. fontFamily= "newfont, serif" ;
为了在使用前显式预加载字体,作者可以将新 FontFace 添加到 FontFaceSet 的操作推迟到加载完成之后
var f= new FontFace( "newfont" , "url(newfont.woff)" , {}); f. load(). then( function ( loadedFace) { document. fonts. add( loadedFace); document. body. style. fontFamily= "newfont, serif" ; });
在这种情况下,首先下载字体资源“newfont.woff”。一旦下载完成,字体就会被添加到文档的 FontFaceSet 中,正文字体被更改,布局引擎使用新的字体资源。
4. FontFaceSource 混合接口
interface mixin {FontFaceSource readonly attribute FontFaceSet ; };fonts Document includes FontFaceSource ;WorkerGlobalScope includes FontFaceSource ;
任何可以以某种方式使用字体的文档、Worker 或其他上下文都必须包含 FontFaceSource 混合接口。上下文的 fonts 属性的值就是它的 字体源,除非另有定义,否则它提供了字体相关操作中使用的所有字体。引用“字体源”的操作必须被解释为引用正在进行操作的相关上下文的 字体源。
对于在这些上下文之一内进行的任何字体相关操作,字体源 中的 FontFace 对象就是其 可用字体显示。
4.1. Worker FontFaceSources
在 Worker 文档中,字体源 最初为空。
注意: FontFace 对象可以按正常方式构建并添加到其中,这会影响 Worker 内的 CSS 字体匹配(例如,在将文本绘制到 OffscreenCanvas 时)。
4.2. 与 CSS 的 @font-face 规则交互
文档的 字体源 的 集合条目 必须最初填充来自 文档或影子根 CSS 样式表 中所有 CSS @font-face 规则的所有 CSS 连接的 FontFace 对象,按文档顺序排列。当 @font-face 规则从样式表中添加或删除,或者包含 @font-face 规则的样式表被添加或删除时,相应的 CSS 连接的 FontFace 对象必须从文档的 字体源 中添加或删除,并保持此顺序。
任何手动添加的 FontFace 对象必须排序在 CSS 连接的 对象之后。
当使用 CSS 连接的 FontFace 对象调用 FontFaceSet 对象的 add() 方法时,如果该对象已在集合中,则该操作必须为空操作;否则,该操作必须不执行任何操作,并抛出 InvalidModificationError。
当使用 CSS 连接的 FontFace 对象调用 FontFaceSet 对象的 delete() 方法时,该操作必须为空操作,并返回 。
注意:即使 FontFace 已被自动从 字体源 中移除,作者仍然可以保留对它的引用。然而,正如 § 2.3 与 CSS 的 @font-face 规则交互 中所指出的,此时该 FontFace 不再是 CSS 连接的。
注意:预期本规范的未来版本也将定义与本地字体交互和查询的方法。
5. API 示例
document. fonts. ready. then( function () { var content= document. getElementById( "content" ); content. style. visibility= "visible" ; });
function drawStuff() { var ctx= document. getElementById( "c" ). getContext( "2d" ); ctx. fillStyle= "red" ; ctx. font= "50px MyDownloadableFont" ; ctx. fillText( "Hello!" , 100 , 100 ); } document. fonts. load( "50px MyDownloadableFont" ) . then( drawStuff, handleError);
function measureTextElements() { // contents can now be measured using the metrics of // the downloadable font(s) } function doEditing() { // content/layout operations that may cause additional font loads document. fonts. ready. then( measureTextElements); }
loadingdone 事件仅在所有字体相关的加载完成且文本排版完成而未导致额外字体加载后才会触发< style > @ font-face { font-family : latin-serif ; src : url ( latinserif . woff ) format ( "woff" ); /* contains no kanji/kana */ } @ font-face { font-family : jpn-mincho ; src : url ( mincho . woff ) format ( "woff" ); } @ font-face { font-family : unused ; src : url ( unused . woff ); } body { font-family : latin-serif , jpn-mincho ; } </ style > < p > 納豆はいかがでしょうか
在这种情况下,用户代理首先下载“latinserif.woff”,然后尝试使用它来绘制日语文本。但由于该字体中不存在日语字形,因此会发生回退,并下载字体“mincho.woff”。仅在第二种字体下载完成且日语文本排版完成后,才会触发 loadingdone 事件。
“未使用的”字体不会被加载,因为没有文本正在使用它,所以 UA 甚至不会尝试加载它。它不会干扰 loadingdone 事件。
变更
自 2014 年 5 月 CSS 字体加载最后征求意见工作草案 以来的变更
- 添加了用于发现字体信息的 IDL。
- 明确了 FontFaceSet.clear() 不会清除 CSS 连接的项目。
- 在简介中提到了 document.fonts。
- 字体加载不仅适用于文档,也适用于影子根。
- 如果指定的字体都不存在,不再抛出错误,因为这不会触发任何字体加载。
- 更好地与 WebIDL 对齐。
- 切换到 constructor() 方法语法。
- 明确了如果匹配字符串为空时匹配字体算法的行为。
- 将 FontFaceSource 转换为 mixin。
- 遗留术语 CanvasProxy 更改为 OffscreenCanvas。
- 将 FontFace 与 @font-face 协调一致,添加了 variationSettings 和 fontDisplay。
- 在 IDL 中一致地使用 [Exposed]。
- 优先使用 CSSOMString 而非 DOMString
- 为 check() 提供了更好的介绍性文本
- 明确了必须允许依赖于最近加载字体的布局操作完成。
- 涵盖触发加载事件时的更多边缘情况。
- 优先使用异步事件队列任务而非同步调用
- fonts.ready 是一个属性,而不是一个函数。
- 区分了不存在的字体和存在但缺乏所需字形的字体。
- 精确列出了几种方法的步骤顺序
- 明确了 load() 和 check() 函数中全局关键字和相对值的处理。
- 解析 src 参数与解析 CSS @font-face src 描述符相同。
- 明确了尝试删除 CSS 连接的字体没有任何效果,并返回 false。
- 明确了添加重复字体没有任何效果。
- 明确了手动添加 FontFace 对象的排序。
- 明确了加载事件仅包括集合中仍然存在的字体。
- 添加了
variationSettings和display,以与 @font-face 同步。 - 将
fontfaces切换为 FrozenArray,以符合正确的 IDL 实践。 - 当加载中的字体被添加到 FontFaceSet 时,触发加载事件并处理 Promise。
- 更正异步算法以使用“队列任务”语言,以确保副作用时序定义良好。
- 更新了几个引用至最新版本。
- 对 IDL 的更正。
- 修正了各种拼写和语法错误。
致谢
Google Fonts 团队的几位成员提供了有关字体加载事件的有益反馈,Boris Zbarsky、Jonas Sicking 和 ms2ger 也是如此。
隐私性考虑
FontFaceSet 对象会泄露有关用户已安装字体的信息,但方式与现有的 @font-face 规则完全相同;没有泄露新的信息,也没有以任何明显更容易的方式进行泄露。
安全性考虑
针对本规范未提出任何安全方面的考虑。