1. 引言
CSS 允许作者通过 @font-face 规则从网页加载自定义字体。 虽然在编写样式表时使用它很简单, 但通过脚本动态使用它就困难得多。
此外,CSS 允许用户代理决定何时实际加载字体; 如果某个字体在页面上 当前 没有被使用, 大多数用户代理不会下载其关联的文件。 这意味着稍后使用该字体时会有延迟, 因为用户代理最终会检测到使用并开始下载和解析字体文件。
本规范定义了一个脚本接口来处理 CSS 中的字体,
允许通过 FontFace
接口轻松创建字体,
并通过脚本加载(通过 document.fonts)。
它还提供了方法来跟踪单个字体的加载状态,
或整个页面上所有字体的加载状态。
该规范中的几项使用了普通的 ES 对象来定义行为, 例如内部使用 Promises 的各种操作, 以及 FontFaceSet 内部使用 Set。 我认为此处的意图是这些对象 (及其原型链)应当是原生的, 不受作者操作的影响。 这是个好意图吗? 如果是,我该如何在规范中表示这一点?
1.1. 值
本规范使用 Promise
,
这些在 ECMAScript
6 中定义。
MDN 提供了一些 关于
Promises 的不错的教程材料。
1.2. 任务源
每当本规范排队一个任务时, 它会将任务排到“字体加载”任务源上。
2. FontFace
接口
FontFace
接口表示一个可用的字体。
CSS @font-face 规则隐式定义了 FontFace 对象,
或者可以从 URL 或二进制数据手动构造。
typedef (ArrayBuffer 或 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 或 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 ; };
需要明确所有提及“文档”的内容,以清楚指代的是哪个文档, 因为对象可能会在文档之间移动。
family
, 类型为 CSSOMStringstyle
, 类型为 CSSOMStringweight
, 类型为 CSSOMStringstretch
, 类型为 CSSOMStringunicodeRange
, 类型为 CSSOMString-
这些属性表示字体的相应方面, 正如在 CSS @font-face 规则中定义的描述符一样。 它们的解析与对应的 @font-face 描述符相同。 它们用于字体匹配算法中, 但除此之外没有任何影响。
例如,具有
FontFace
的style
值为"italic"
的对象 表示 一个斜体字体; 它并不会使 该字体变为斜体。在获取时,返回与此属性关联的字符串。
在设置时,根据 CSS 语法解析字符串, 如果不匹配语法, 则抛出
SyntaxError
异常; 否则,将该属性设置为解析值的序列化结果。 variant
, 类型为 CSSOMStringfeatureSettings
, 类型为 CSSOMStringvariationSettings
, 类型为 CSSOMStringdisplay
, 类型为 CSSOMStringascentOverride
, 类型为 CSSOMStringdescentOverride
, 类型为 CSSOMStringlineGapOverride
, 类型为 CSSOMString-
这些属性与 CSS @font-face 规则中的相应描述符含义相同,解析方式也相同。
它们在支持这些功能的字体中打开或关闭特定的功能。 与之前的属性不同, 这些属性实际上会影响字体本身。
在获取时,返回与此属性关联的字符串。
在设置时,根据 CSS 语法解析字符串, 如果不匹配语法, 则抛出
SyntaxError
异常; 否则,将该属性设置为解析值的序列化结果。 status
, 类型为 FontFaceLoadStatus, 只读-
此属性反映字体的当前状态。 对于新创建的
FontFace
, 它必须是 "unloaded"。它可以通过作者显式请求加载字体(例如通过
load()
方法)或通过用户代理的隐式操作(例如用户代理检测到需要该字体来绘制一些文本)而更改。 loaded
, 类型为 Promise<FontFace>, 只读-
此属性反映字体的
[[FontStatusPromise]]
。
所有 FontFace
对象都包含一个内部的 [[FontStatusPromise]]
槽,
用于跟踪字体的状态。
它最初为 pending,
当字体成功加载并解析,或遇到错误时,它会完成或被拒绝。
所有 FontFace
对象还包含内部的 [[Urls]]
和 [[Data]]
槽,
其中一个为 null
,另一个不为 null
(根据构造函数传入的数据确定哪个槽非空)。
2.1. 构造器
FontFace
可以通过指向字体文件的 URL
或包含字体二进制表示的 ArrayBuffer
(或 ArrayBufferView
)
来构造。
当调用 FontFace(family, source, descriptors)
方法时,
执行以下步骤:
-
令 font face 是一个新的
FontFace
对象。 设置 font face 的status
属性为"unloaded"
, 将其内部的[[FontStatusPromise]]
槽设置为一个新的 pendingPromise
对象。解析
family
参数, 以及descriptors
参数的成员, 根据 CSS @font-face 规则的相应描述符的语法解析它们。 如果source
参数是CSSOMString
, 则根据 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 现在表示已解析的字体; 使用 font face 完成 font face 的
[[FontStatusPromise]]
, 并将其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()
方法
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]]
槽的值, 按照 [CSS-FONTS-3] 中定义的方式尝试加载字体, 就像它是 @font-face 规则的 src 描述符的值一样。 -
当加载操作完成时,
无论成功与否,
将任务排队以同步执行以下步骤:
-
如果加载失败,
使用名为 "NetworkError" 的 DOMException 拒绝 font face 的
[[FontStatusPromise]]
并将 font face 的status
属性设置为 "error"。对于每个包含 font face 的
FontFaceSet
:-
将 font face 添加到
FontFaceSet
的[[FailedFonts]]
列表中。 -
从
FontFaceSet
的[[LoadingFonts]]
列表中移除 font face。 如果 font 是该列表中的最后一项 (因此该列表现在为空),则将 FontFaceSet 切换为已加载状态。
-
-
否则,font face 现在表示已加载的字体;
使用 font face 完成 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()
方法,如本文所述。
注意: 某些用户代理使用 "字体缓存",
以避免在同一页面或同一来源的多个页面上多次下载相同的字体。
多个 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 连接的。
内部的 [[Urls]]
槽位的 FontFace
对象被设置为 @font-face 规则的 src 描述符的值,并反映对 src 描述符所做的任何更改。
除此之外,由 CSS @font-face 规则创建的 FontFace
对象与手动创建的对象相同。
如果从文档中移除 @font-face 规则,其对应的 FontFace
对象将不再是
CSS 连接的。这种连接无法通过任何方式恢复(但是将
@font-face 重新添加到样式表中会创建一个全新的 FontFace
对象,该对象是
CSS 连接的)。
如果 @font-face 规则的 src 描述符被更改为新值,则原来的已连接的 FontFace
对象必须停止与
CSS 连接。必须创建一个新的 FontFace
对象来反映其新的 src 并与 @font-face 进行 CSS
连接。(这也会从它们出现在的任何 字体来源
中移除旧的并添加新的 FontFace
对象。)
2.4. 字体信息的发现
FontFace
对象包含关于字体文件内容的多种只读信息。
[Exposed =(Window ,Worker )]interface { /* CSS 工作组仍在讨论这里的内容 */ }; [
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 (); // 加载状态更改的事件attribute EventHandler ;
onloading attribute EventHandler ;
onloadingdone attribute EventHandler ; // 检查并启动加载(如果合适) // 并在所有加载完成时实现 promise
onloadingerror Promise <sequence <FontFace >>load (CSSOMString font ,optional CSSOMString text = " "); // 返回字体列表中的所有字体是否已加载 // (如果不可用则不启动加载)boolean check (CSSOMString font ,optional CSSOMString text = " "); // 字体加载和布局操作完成时的异步通知readonly attribute Promise <FontFaceSet >ready ; // 加载状态,“loading”表示一个或多个字体正在加载,否则为“loaded”readonly attribute FontFaceSetLoadStatus ; };
status
ready
, 类型为 Promise<FontFaceSet>, 只读-
此属性反映
FontFaceSet
的[[ReadyPromise]]
槽。参见 § 3.4 ready 属性 了解此
Promise
的更多详细信息及其使用。 FontFaceSet(initialFaces)
-
FontFaceSet
构造函数被调用时, 必须迭代其initialFaces
参数, 并将每个值添加到其 set entries 中。 - 迭代顺序
-
在迭代时, 所有 CSS 连接的
FontFace
对象必须首先出现, 以其连接的 @font-face 规则的文档顺序, 后面跟着未 CSS 连接的FontFace
对象, 以插入顺序排列。 - set entries
-
如果
FontFaceSet
是 字体来源, 则其 set entries 会按照在 § 4.2 与 CSS 的 @font-face 规则交互 中指定的方式进行初始化。否则,其 set entries 最初是空的。
add(font)
-
调用
add()
方法时, 执行以下步骤:-
如果 font 已存在于
FontFaceSet
的 set entries 中, 则立即跳到该算法的最后一步。 -
如果 font 是 CSS 连接的, 抛出
InvalidModificationError
异常, 并立即退出该算法。 -
将 font 参数添加到
FontFaceSet
的 set entries 中。 -
如果 font 的
status
属性为“loading”:-
如果
FontFaceSet
的[[LoadingFonts]]
列表为空,则 将 FontFaceSet 切换为 loading 状态。 -
将 font 添加到
FontFaceSet
的[[LoadingFonts]]
列表中。
-
-
返回
FontFaceSet
。
-
delete(font)
-
调用
delete()
方法时, 执行以下步骤:-
如果 font 是 CSS 连接的, 返回
并立即退出该算法。false -
将 deleted 设为从
FontFaceSet
的 set entries 中移除 font 的结果。 -
如果 font 存在于
FontFaceSet
的[[LoadedFonts]]
, 或[[FailedFonts]]
列表中, 则将其移除。 -
如果 font 存在于
FontFaceSet
的[[LoadingFonts]]
列表中, 则将其移除。 如果 font 是该列表中的最后一项(因此列表现在为空),将 FontFaceSet 切换为 loaded 状态。 -
返回 deleted。
-
clear()
-
调用
clear()
方法时, 执行以下步骤:-
从
FontFaceSet
的 set entries 中移除所有非 CSS 连接的 项, 以及[[LoadedFonts]]
列表和[[FailedFonts]]
列表中的所有项。 -
如果
FontFaceSet
的[[LoadingFonts]]
列表不为空, 则将所有项移除, 然后 将 FontFaceSet 切换为 loaded 状态。
-
FontFaceSet
对象还具有内部的 [[LoadingFonts]]
、[[LoadedFonts]]
,
和 [[FailedFonts]]
槽,
它们都初始化为空列表,
还有一个 [[ReadyPromise]]
槽,
其被初始化为一个新的挂起的 Promise
。
因为字体系列仅在使用时才加载, 内容有时需要了解字体加载的时机。 作者可以使用此处定义的事件和方法来更好地控制依赖于特定字体可用性的操作。
FontFaceSet
如果符合以下任一条件,则视为 依赖环境:
-
文档仍在加载中
-
文档有挂起的样式表请求
-
文档有挂起的布局操作,可能导致用户代理请求字体,或依赖于最近加载的字体
注意: 一旦 FontFaceSet
停止 依赖环境,
只要没有其他更改文档的内容,
作者可以依赖测量时大小/位置是“正确的”。
如果上述条件无法完全捕获此保证,
则需要对其进行修改以实现该保证。
3.1. 事件
字体加载事件使得响应整个文档的字体加载行为变得更加简单,而不必对每个字体进行单独监听。
loading
事件在文档开始加载字体时触发,
而 loadingdone
和 loadingerror
事件在文档完成加载字体时触发,分别包含成功加载的字体和加载失败的字体。
以下是 FontFaceSet
对象作为 IDL 属性必须支持的事件处理程序(及其相应的事件类型):
事件处理程序 | 事件类型 |
---|---|
onloading
| loading
|
onloadingdone
| loadingdone
|
onloadingerror
| loadingerror
|
要在 FontFaceSet
target 上触发名为 e 的字体加载事件,并可选带有 font faces,意味着使用符合以下条件的 FontFaceSetLoadEvent
接口触发一个简单事件名为 e。
当被要求为给定的 FontFaceSet
将
FontFaceSet 切换为 loading时,用户代理必须执行以下步骤:
- 让 font face set 为给定的
FontFaceSet
。 - 将 font face set 的
status
属性设置为“loading”。 - 如果 font face set 的
[[ReadyPromise]]
槽当前持有一个已实现的 promise,则替换为一个新的挂起的 promise。 - 排队任务以在 font face set 上触发一个字体加载事件,名为
loading
。
当被要求为给定的 FontFaceSet
将
FontFaceSet 切换为 loaded时,用户代理必须执行以下步骤:
-
让 font face set 为给定的
FontFaceSet
。 -
如果 font face set 依赖环境,则将其标记为依赖环境,并退出此算法。
-
将 font face set 的
status
属性设置为“loaded”。 -
用 font face set 完成 font face set 的
[[ReadyPromise]]
属性的值。 -
排队任务以同步执行以下步骤:
-
让 loaded fonts 为 font face set 的
[[LoadedFonts]]
槽的内容(可能为空)。 -
让 failed fonts 为 font face set 的
[[FailedFonts]]
槽的内容(可能为空)。 -
将
[[LoadedFonts]]
和[[FailedFonts]]
槽重置为空列表。 -
触发一个字体加载事件,名为
loadingdone
,在 font face set 上并带有 loaded fonts。 -
如果 font face set 的 failed fonts 不为空,触发一个字体加载事件,名为
loadingerror
,在 font face set 上并带有 failed fonts。
-
每当 FontFaceSet
从 依赖环境变为不再依赖环境时,用户代理必须执行以下步骤:
-
如果
FontFaceSet
依赖环境,并且其[[LoadingFonts]]
列表为空,将 FontFaceSet 切换为 loaded。 -
如果
FontFaceSet
依赖环境,取消标记它。
如果请求从 FontFaceSet source 中找到匹配的字体,给定字体字符串 font,可选一些示例文本 text,并可选一个 允许系统字体 标志,执行以下步骤:
- 解析 font,使用 font 属性的 CSS
值语法。
如果出现语法错误,
返回语法错误。
如果解析后的值是 CSS-wide 关键字, 返回语法错误。
将所有相对长度对对应属性的初始值进行绝对化。 (例如,相对字体权重如 bolder 是相对于初始值 normal 来评估的。)
- 如果未显式提供 text, 让它是一个包含单个空格字符(U+0020 SPACE)的字符串。
- 让 font family list 为从 font 解析出的字体系列列表, 并让 font style 为从 font 解析出的其他字体样式属性。
- 让 available font faces 为 source 中的可用字体。 如果指定了 允许系统字体 标志, 则将所有系统字体添加到 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()
方法
load()
方法属于 FontFaceSet
,用于确定给定字体列表中的所有字体是否已加载并可用。如果有任何字体是可下载字体且尚未加载,用户代理将启动这些字体的加载。它返回一个
Promise,当所有字体加载并可以使用时会被满足,如果任何字体加载失败,则会被拒绝。
当 load
( font
, text
)
方法被调用时,执行以下步骤:
- 令 font face set 为调用此方法的
FontFaceSet
对象。令 promise 为一个新创建的 promise 对象。 - 返回 promise。其余步骤异步完成。
- 查找匹配的字体,从 font face set 中使用传递给函数的
font
和text
参数,令 font face list 为返回值(忽略 found faces 标志)。如果返回了语法错误,使用 SyntaxError 异常拒绝 promise 并终止这些步骤。 - 排队任务以同步执行以下步骤:
- 对 font face list 中的所有字体,调用它们的
load()
方法。 - 以 font face list 中每个字体的
[[FontStatusPromise]]
等待结果的顺序,解决 promise。
- 对 font face list 中的所有字体,调用它们的
3.3. check()
方法
check()
方法属于 FontFaceSet
,用于确定是否可以“安全地”渲染一些提供的文本与特定的字体列表,这样可以防止“字体切换”在之后发生。如果给定的文本/字体组合能在不尝试使用任何未加载或正在加载的字体的情况下渲染,此方法将返回
true;否则,返回 false。
-
如果指定的字体存在,但由于它们的 unicode-range 未覆盖所提供的文本,所有可能的字体样式都被排除,则该方法返回
true
,因为文本将使用用户代理的后备字体渲染,不会触发任何字体加载。 -
同样,如果指定的字体不存在(例如,名称拼写错误),该方法也返回
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 中所有字体的
status
属性为“loaded”或是系统字体,则返回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] 中的字体匹配算法时,它匹配的字体集必须严格为文档的 字体源中的字体集合,以及任何本地字体。
当用户代理需要加载某个字体时,必须通过调用相应 load()
方法加载 FontFace
对象。
(这意味着它必须运行相同的算法,而不是直接调用对象中 load
属性当前存储的值。)
FontFaceSet
中时,字体即为可用。向样式表添加一个新的 @font-face 规则也会向 FontFaceSet
添加一个新的 FontFace
对象到
Document
对象中。
向样式表添加新的 @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
意味着字体将永远不会被加载,文本将以默认的衬线字体显示:
var f= new FontFace( "newfont" , "url(newtest.woff)" , {}); /* 新的 {{FontFace}} 未添加到 {{FontFaceSet}}, 因此 'font-family' 属性无法看到它, 将使用衬线字体 */ 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 ;
任何可以以某种方式使用字体的文档、工作者或其他上下文都必须包含 FontFaceSource
混入。上下文的 fonts
属性的值是它的 字体源,除非另有定义,它提供了所有用于字体相关操作的字体。引用“字体源”的操作必须解释为引用相关上下文中发生操作的 字体源。
对于在这些上下文中发生的任何与字体相关的操作,字体源中的 FontFace
对象是它的
可用字体。
4.1. Worker 中的 FontFaceSources
在 Worker 文档中,字体源最初是空的。
注意:可以像往常一样构造 FontFace
对象并将其添加到字体源中,这会影响 Worker 内的 CSS 字体匹配(例如,将文本绘制到 OffscreenCanvas
)。
4.2. 与 CSS 的 @font-face 规则的交互
文档的 字体源的集合条目必须初始填充所有来自文档或影子根 CSS 样式表中的
CSS @font-face 规则的 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() { // 内容现在可以使用可下载字体的度量来测量 } function doEditing() { // 内容/布局操作可能会导致额外的字体加载 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
事件才会触发。
“unused” 字体没有被加载,但没有文本使用它,因此用户代理甚至没有尝试加载它。它不会干扰 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 时触发加载事件并处理 promises。
- 修正了异步算法以使用“排队任务”语言,确保副作用的时间明确。
- 更新了多个引用到最新版本。
- 对 IDL 进行了修正。
- 修正了各种拼写错误和语法错误。
致谢
Google Fonts 团队的几位成员对字体加载事件提供了有益的反馈,Boris Zbarsky、Jonas Sicking 和 ms2ger 也同样提供了帮助。
隐私考虑
FontFaceSet
对象会泄露有关用户已安装字体的信息,但与现有的 @font-face 规则的方式完全相同;并没有泄露新的信息,也没有在任何意义上使这种泄露变得更容易。
安全性考虑
针对本规范没有提出任何安全性方面的考虑。