【免费下载链接】webfontloader
Web Font Loader gives you added control when using linked fonts via @font-face.
项目地址:
https://gitcode.com/gh_mirrors/we/webfontloader
点击查看 免费下载
Web Font Loader(webfontloader)是一个为 @font-face 链接字体提供统一加载接口与标准事件系统的 JavaScript 库:无论字体来自 Google Fonts、Typekit、Fonts.com、Fontdeck 还是自托管 Web Fonts,它都以一致的 WebFont.load() 配置驱动加载,并通过 CSS 类名与 JS 回调两种方式通知你字体的 loading / active / inactive 状态。读完本文,你将掌握同步与异步引入方式、六类字体事件的含义与用法、六大模块的完整配置参数,以及仓库源码层面字体检测与超时控制的底层原理。
快速上手(Get Started)
通过 CDN 引入并加载 Google 字体
最简用法:在页面中引入 Web Font Loader 脚本,然后调用 WebFont.load() 并告知需要加载的字体族。以下示例通过 Google Hosted Libraries 引入库,并加载 Google Fonts 的 Droid Sans 与 Droid Serif:
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"></script>
<script>
WebFont.load({
google: {
families: ['Droid Sans', 'Droid Serif']
}
});
</script>
也可以把 script 的 src 改为 https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js 来始终拉取最新的 1.x 版本。需要说明的是:这种写法版本号不精确,虽然总会加载最新的 1.x 版本,但缓存时间更短,以便页面及时获得更新。生产环境出于性能考虑,官方建议在 URL 中写死明确版本号(如 1.6.26),需要升级时手动更新 URL 中的版本号即可。仓库当前版本为 1.6.28(见 package.json)。
Web Font Loader 同时也发布在 jsDelivr 与 CDNJS 两个 CDN 上,可按需选用。
异步加载与 FOUT
如果希望加载脚本本身不阻塞页面,可以像下面这样异步引入(以 Typekit 为例):
<script>
WebFontConfig = {
typekit: { id: 'xxxxxx' }
};
(function(d) {
var wf = d.createElement('script'), s = d.scripts[0];
wf.src = 'https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js';
wf.async = true;
s.parentNode.insertBefore(wf, s);
})(document);
</script>
异步方式能避免 JavaScript 加载阻塞页面渲染,但要注意:脚本异步执行时,页面其余部分可能先于 Web Font Loader 加载执行,从而出现"无样式文本闪烁"(Flash of Unstyled Text,简称 FOUT)。
规避 FOUT 更稳妥的做法是同步引入:同步加载时,WebFont.load 一经调用就会立即在 <html> 元素上设置 wf-loading 类,浏览器会等待脚本加载完成后才继续渲染其余内容,从而避免 FOUT。
从源码看,wf-loading 类确实是在模块初始化之前同步派发的:在 webfont.js 的 load_ 方法中,eventDispatcher.dispatchLoading() 被注释明确标注为"在初始化模块之前立即派发,确保 loading 事件是同步的"。
通过 npm / CommonJS 使用
Web Font Loader 也发布在 npm 上,可作为 CommonJS 模块使用:
npm install webfontloader
var WebFont = require('webfontloader');
WebFont.load({
google: {
families: ['Droid Sans', 'Droid Serif']
}
});
仓库的 initialize.js 展示了导出逻辑:它导出 { 'load': … } 对象,支持 AMD(define.amd)、CommonJS(module.exports)以及全局 window['WebFont'] 三种形态;在纯浏览器全局形态下,若检测到已存在的全局 WebFontConfig 变量,会自动调用 load 加载它。
配置总览(Configuration)
Web Font Loader 的配置由全局变量 WebFontConfig 定义,或直接作为参数传给 WebFont.load 方法。配置内容包含两部分:
- 各字体提供商(Provider)要加载的字体;
- 各事件的回调函数。
使用异步加载方式时,必须在加载 Web Font Loader 脚本之前先定义全局变量 WebFontConfig(如前文的异步示例)。
从模块加载器的实现看,配置中每一个"顶级键"都会与已注册的模块名进行匹配:fontmoduleloader.js 遍历 configuration 的所有自有属性,凡是命中已注册模块名(custom、fontdeck、monotype、typekit、google)的键,就用该键的值实例化对应模块。这也是"可以同时混用多个 Provider"的原因——同一份配置里可以并列写多个模块键。
事件系统(Events)
Web Font Loader 提供了一套可供开发者挂接的事件系统,以 CSS 类名和 JavaScript 回调两种形态通知字体加载进度。
事件清单
| loading | 所有字体已被请求时触发 |
| active | 字体渲染完成时触发 |
| inactive | 浏览器不支持链接字体,或没有任何字体加载成功时触发 |
| fontloading | 每加载一个字体触发一次 |
| fontactive | 每渲染一个字体触发一次 |
| fontinactive | 某个字体无法加载时触发 |
CSS 事件:html 元素上的类名
CSS 事件以 <html> 元素上的类名呈现,可用的类名如下:
.wf-loading
.wf-active
.wf-inactive
.wf-<familyname>-<fvd>-loading
.wf-<familyname>-<fvd>-active
.wf-<familyname>-<fvd>-inactive
其中 <familyname> 会被替换为字体族名的"净化版本":空格与下划线被移除,所有字符转为小写。例如 Droid Sans 变为 droidsans。该逻辑对应 cssclassname.js 的 sanitize 方法:name.replace(/[\\W_]+/g, '').toLowerCase(),即删除所有非单词字符与下划线后转小写;测试用例 cssclassname_spec.js 中验证了 ' My Family ' → myfamily、'_My+Family!-' → myfamily 等行为。
<fvd> 是 Font Variation Description(字体变体描述,简称 FVD)的缩写,用于简写某种字体的样式与字重。例如:
/* n4 */
@font-face { font-style: normal; font-weight: normal; }
/* i7 */
@font-face { font-style: italic; font-weight: bold; }
注意:font-weight: normal 对应 400,font-weight: bold 对应 700。如果没有显式指定样式/字重,默认使用 n4(即 font-style: normal; font-weight: normal;)。
FVD 的解析逻辑位于 font.js:Font 构造函数通过 /^([nio])([1-9])$/i 正则解析变体描述,其中样式位支持 n(normal)、i(italic)、o(oblique),字重位是 1–9 的数字;getCssWeight() 将其还原为 '400'、'700' 这样的 CSS 字重值。
同一页面多次加载字体时,CSS 类名会持续更新以反映页面当前状态:
- 只要有字体正在被请求,全局 wf-loading 类就会存在(即使其他字体已 active 或 inactive);
- 只有当页面上没有任何字体渲染成功时,才会应用 wf-inactive;
- 否则应用 wf-active(即使部分字体 inactive)。
对应的类名管理逻辑在 eventdispatcher.js 中实现,例如 dispatchFontActive 会移除 loading 与 inactive 类并追加 active 类(第 95-110 行),而 dispatchInactive 只在 active 类不存在时才追加 inactive 类(第 142-160 行)。spec/core/eventdispatcher_spec.js 用完整的 Jasmine 用例覆盖了这些"类名互相覆盖"的边界场景。
JavaScript 事件:配置对象上的回调
JavaScript 事件以 WebFontConfig 配置对象上的回调函数实现:
WebFontConfig = {
loading: function() {},
active: function() {},
inactive: function() {},
fontloading: function(familyName, fvd) {},
fontactive: function(familyName, fvd) {},
fontinactive: function(familyName, fvd) {}
};
fontloading、fontactive、fontinactive 三个回调会收到对应字体的族名与 FVD。事件分发核心在 eventdispatcher.js 的 dispatch_ 方法:当事件开关开启且配置中存在对应回调时,携带字体名与变体调用回调。
仓库自带的事件演示页 events.html 同时展示了 CSS 类钩子(html.wf-loading、html.wf-droidsans-n4-active 等选择器)与 JS 回调进度列表(fontloading/fontactive/fontinactive 事件日志)的完整用法,可作为本地联调参考。
关闭类名或事件
可以通过 classes 参数关闭 html 元素上的类名设置(默认为 true):
WebFontConfig = {
classes: false
};
也可以通过 events 参数关闭字体事件回调(默认为 true):
WebFontConfig = {
events: false
};
如果 events 与 classes 同时关闭,Web Font Loader 将不再进行字体监听(font watching),只负责向文档插入 @font-face 规则。 这可以从 webfont.js 的 onModuleReady_ 中看到:只有 this.classes_ || this.events_ 为真时,才会调用 fontWatcher.watchFonts 启动监听。
超时机制(Timeouts)
网络并非 100% 可靠,字体可能加载失败。当字体无法渲染时,会触发 fontinactive 事件;如果至少一个字体渲染成功,则触发 active 事件,否则触发 inactive 事件。
说明:README 原文中此处描述为"5 秒后触发 fontinactive",而同一文档的下一段及当前仓库源码给出的默认超时均为 3000 毫秒(3 秒),请以后者(3 秒默认值)为准。
可以通过 WebFontConfig 上的 timeout 选项修改默认超时:
WebFontConfig = {
google: {
families: ['Droid Sans']
},
timeout: 2000 // Set the timeout to two seconds
};
timeout 的单位是毫秒,不提供时默认为 3000 毫秒。
源码中超时值的传递路径很清晰:webfont.js 把 configuration['timeout'] 传给 FontWatcher;fontwatchrunner.js 中 this.timeout_ = opt_timeout || 3000 给出默认值,并在 hasTimedOut_() 中用 goog.now() – this.started_ >= this.timeout_ 判断是否超时。spec/core/fontwatcher_spec.js 中也验证了 timeout 会原样传递给 FontWatchRunner。
Iframes 与多窗口管理(context)
通常情况下,最简单的做法是在每个需要字体的窗口中都引入一份 Web Font Loader 副本,让每个窗口管理自己的字体。但如果你希望由单个窗口统一管理多个同源子窗口或 iframe(例如用 JavaScript 动态构建的 iframe)的字体,Web Font Loader 同样支持:使用可选的 context 配置项,传入目标窗口的引用:
WebFontConfig = {
google: {
families: ['Droid Sans']
},
context: frames['my-child']
};
这是一个高级配置项,大多数使用场景并不需要。其底层实现见 webfont.js:var context = configuration['context'] || this.mainWindow_,随后用主窗口与目标窗口构造 DomHelper(加载窗口通过 domhelper.js 的 loadWindow_ 控制),后续样式表、脚本与检测元素都会被注入到目标窗口中。
模块系统(Modules)
Web Font Loader 提供了模块系统:任何 Web 字体提供商都可以通过贡献代码让自己的字体被加载,因此同一页面可以同时混用多个 Provider。目前库内置支持的 Provider 及其具体配置如下。
模块注册的入口在 initialize.js:五个模块(custom、fontdeck、monotype、typekit、google)通过编译期 INCLUDE_*_MODULE 开关决定是否打包,每个模块通过 addModule 注册到 FontModuleLoader。
Adobe Edge Web Fonts
使用 Adobe Edge Web Fonts 时,复用 typekit 模块:在 id 参数中传入用分号连接起来的字体列表,并把 api 参数指向 Edge Web Fonts 的 URL。
WebFontConfig = {
typekit: {
id: 'adamina;advent-pro',
api: '//use.edgefonts.net'
}
};
Custom(自托管 / 任意外部样式表)
要从任意外部样式表加载字体,使用 custom 模块。需要指定要加载的字体族名,以及(可选地)提供这些字体 @font-face 声明的样式表 URL。
可以在族名后用冒号追加以逗号分隔的多个变体(FVD 表示法),从而精确控制加载与监听的字体变体:
WebFontConfig = {
custom: {
families: ['My Font', 'My Other Font:n4,i4,n7'],
urls: ['/fonts.css']
}
};
在这个例子中,fonts.css 可能长这样:
@font-face {
font-family: 'My Font';
src: …;
}
@font-face {
font-family: 'My Other Font';
font-style: normal;
font-weight: normal; /* or 400 */
src: …;
}
@font-face {
font-family: 'My Other Font';
font-style: italic;
font-weight: normal; /* or 400 */
src: …;
}
@font-face {
font-family: 'My Other Font';
font-style: normal;
font-weight: bold; /* or 700 */
src: …;
}
如果字体已经包含在页面中某个其他样式表里,也可以省略 urls 数组、只写字体族名来启动加载。只要这些名字与 families 数组中声明的名称一致,对应的加载类就会被正确应用到 html 元素上:
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.10/webfont.js"></script>
<script>
WebFont.load({
custom: {
families: ['My Font']
}
});
</script>
<style type="text/css">
@font-face {
font-family:"My Font";
src:url("assets/fonts/my_font.woff") format("woff");
}
</style>
custom 模块还支持自定义"测试字符串"(test strings),即用于判断字体是否加载成功的文本。这可用于加载自定义子集、或字形位于 Unicode 私用区(PUA)的字体:
WebFontConfig = {
custom: {
families: ['My Font'],
testStrings: {
'My Font': '\\uE003\\uE005'
}
}
};
测试字符串必须按字体逐个指定,且至少包含一个字符。若未指定,则使用默认测试字符串 BESbswy。从源码看:fontwatchrunner.js 定义 DEFAULT_TEST_STRING = 'BESbswy',并注释说明这些字符在默认回退字体栈之间的宽度差异很大,便于区分字体是否真正渲染;custom.js 实现中,families 数组里每一项按 : 拆分族名与变体(变体再按 , 拆分),urls 通过 StyleSheetWaiter 等待样式表就绪后再回调字体列表。
Fontdeck
使用 Fontdeck 模块时,指定你网站的 ID(可在账户设置中的网站页面找到):
WebFontConfig = {
fontdeck: {
id: 'xxxxx'
}
};
源码 fontdeck.js 中,脚本 URL 由默认 API 地址 https://f.fontdeck.com/s/css/js/ 拼接当前主机名与项目 ID 构成;Fontdeck 通过回调注入字体数据后,模块用 Font.parseCssVariation('font-weight:…;font-style:…') 解析每个字体的变体描述。
Fonts.com
使用 Fonts.com web fonts 时,指定你的 Project ID:
WebFontConfig = {
monotype: {
projectId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
version: 12345, // (optional, flushes the CDN cache)
loadAllFonts: true //(optional, loads all project fonts)
}
};
Fonts.com 模块有一个可选的 version 参数,充当缓存击穿(cache-buster,即通过 URL 查询参数强制刷新 CDN 缓存);可选的 loadAllFonts 用于加载项目全部字体。默认情况下,Fonts.com 模块只加载页面上实际用到的字体。
从源码看:monotype.js 中脚本地址默认为 https://fast.fonts.net/jsapi,version 会以 ?v= 查询参数拼接到 URL;加载完成后模块通过全局钩子 __mti_fntLst + projectId 获取字体列表,并把配置暴露给 __MonotypeConfiguration__ 供 Fonts.com 读取。
使用 Google 的 Font API 时,直接写出要加载的字体族名。可以使用与 Font API 相同的语法指定样式。请注意:Google 模块不支持 custom 模块所用的 FVD 语法。
WebFontConfig = {
google: {
families: ['Droid Sans', 'Droid Serif:bold']
}
};
有时你请求的字体没有默认字重(如 400),为了让字体事件正常工作,需要显式请求想要的变体(如 300、700 等):
WebFontConfig = {
google: {
families: ['Open Sans Condensed:300,700']
}
};
如果需要指定默认以外的字符子集(例如在拉丁之外再加希腊文),需要在族名字符串后用冒号追加子集字符串,子集名用逗号分隔(遵循 Google 文档):
WebFontConfig = {
google: {
families: ['Open Sans Condensed:300,700:latin,greek']
}
};
还可以提供 text 参数执行字符级子集化(只请求这些字符):
WebFontConfig = {
google: {
families: ['Droid Sans', 'Droid Serif'],
text: 'abcdefghijklmnopqrstuvwxyz!'
}
};
text 子集化功能仅 Google 模块可用。
从源码看,Google 模块的 URL 构建位于 fontapiurlbuilder.js:默认 API 地址为 https://fonts.googleapis.com/css,族名中的空格会替换为 +,多个族名用 %7C(转义的 |)连接,子集以 &subset= 参数、text 以 &text= 参数(encodeURIComponent 编码)拼入 URL。变体解析则在 fontapiparser.js:它维护了 WEIGHTS 表(如 bold→7、regular→4、light→3)、STYLES 表(italic→i、normal→n)以及 INT_FONTS 测试字符串表(latin 用默认 BESbswy,cyrillic 用 \\u0439\\u044f\\u0416,greek 用 \\u03b1\\u03b2\\u03a3 等),将 Open Sans Condensed:300,700 这类写法归一化为 n3、n7 等 FVD。spec/modules/google/fontapiparser_spec.js 对字重、斜体、子集、拼写错误回退等解析场景都有覆盖。
Typekit
使用 Typekit 时,通过 Kit ID 指定要加载的 Kit(可在 Typekit 的 Kit Editor 界面找到):
WebFontConfig = {
typekit: {
id: 'xxxxxx'
}
};
提醒: Typekit 自家的 JavaScript 本身就是基于 Web Font Loader 库构建的,并且已经提供了完全相同的字体事件功能。如果你只用 Typekit,应直接使用其嵌入代码;只有当你在同一页面还需要加载其他提供商的 Web 字体时,才需要通过 Web Font Loader 集成。
源码 typekit.js 中,脚本 URL 默认指向 https://use.typekit.net/<id>.js(可用 api 覆盖);加载成功后从 Typekit.config.fn 读取字体与变体列表,然后以 { events: false, classes: false, async: true } 调用 Typekit.load 去加载字体,同时避免与自身字体监听重复。
浏览器支持(Browser Support)
每个浏览器对 @font-face 的支持程度各不相同。Web Font Loader 通过 User Agent 字符串判断浏览器对 Web 字体的支持能力。UA 字符串可能声称支持某种字体格式而实际上并不支持,这在开启"桌面模式"的移动浏览器上尤其常见(这类浏览器通常把自己标识为 Linux 上的 Chrome):提供商可能因为真正的桌面 Chrome 支持 WOFF 而向该设备下发 WOFF 字体,但移动浏览器实际不支持。Web Font Loader 不设计处理这类情况,默认信任 UA 字符串中的声明;各 Web 字体提供商可以在基础功能之上针对这些特例自行处理。
行为规则总结如下:
- 若 Web Font Loader 判定当前浏览器不支持 @font-face,则触发 inactive 事件;
- 从多个 Provider 加载字体时,各 Provider 对某浏览器的支持情况可能不同:若当前浏览器支持 @font-face,且至少一个 Provider 能提供字体,则加载该 Provider 的字体,完成后触发 active 事件;
- 对受支持 Provider 加载的字体,触发 fontactive 事件;对不支持当前浏览器的 Provider 提供的字体,触发 fontinactive 事件。
例如:
WebFontConfig = {
providerA: 'Family1',
providerB: 'Family2'
};
若 providerA 能向该浏览器提供字体而 providerB 不能,则 Family2 触发 fontinactive;Family1 加载完成后触发 fontactive,同时触发 active 事件。
源码级补充:两种字体监听实现
仓库在字体"是否渲染"的判定上提供了两套实现,可作为理解浏览器支持的参考:
- 原生路径 NativeFontWatchRunner:fontwatcher.js 的 shouldUseNativeLoader() 检测浏览器是否支持 CSS Font Loading API(window.FontFace),并针对已知问题做了规避:Firefox 42 及以下版本禁用,Safari 10 的 OS X 10.x 版本禁用;其余支持 FontFace 的浏览器走原生实现。原生实现(nativefontwatchrunner.js)通过 document.fonts.load(…) + Promise.race 实现加载判定,默认超时同样为 3000ms。
- 回退路径 FontWatchRunner:非原生浏览器走 fontwatchrunner.js 的"标尺测量"方案。它创建四个离屏 span 标尺元素(fontruler.js 中以 position:absolute; top/left:-9999px; font-size:300px 隐藏),分别以"目标字体+serif 回退""目标字体+sans-serif 回退""纯 serif""纯 sans-serif"渲染 BESbswy 测试字符串,每 50ms 轮询宽度(asyncCheck_)。若目标字体尚未加载,其宽度与回退字体一致;一旦宽度变化,即判定字体渲染成功。此外还针对 WebKit 536.11 及更早版本的 fallback bug 做了兼容判断。
测试与验证
仓库使用 Jasmine 编写测试(spec/ 目录),通过 PhantomJS 运行,测试命令定义在 package.json 的 scripts.test:
npm test
# 等价于:phantomjs tools/jasmine-phantomjs/jasmine-phantomjs.js spec/index.html
与本 README 内容直接相关的测试用例包括:
- eventdispatcher_spec.js:覆盖六个事件回调与 wf-* 类名的设置/移除、loading/active/inactive 类互相覆盖、classes/events 关闭等全部边界行为;
- cssclassname_spec.js:验证族名净化规则与分隔符;
- fontwatcher_spec.js:验证零字体、单字体、多字体、混合成败、测试字符串传递、timeout 透传以及原生加载器在各 UA 下的开关判定;
- fontapiparser_spec.js:验证 Google 模块字重/斜体/子集解析与测试字符串选取。
版权与许可
Web Font Loader Copyright (c) 2010-2017 Adobe Systems Incorporated, Google Incorporated,采用 Apache License 2.0 许可(见 LICENSE)。源码核心位于 src/core 与 src/modules,模块编译清单见 modules.yml,完整变更历史见 CHANGELOG。
赞
【免费下载链接】webfontloader
Web Font Loader gives you added control when using linked fonts via @font-face.
项目地址:
https://gitcode.com/gh_mirrors/we/webfontloader
点击查看 免费下载
相关推荐
AsrTools:高效语音识别工具的技术解析与实践指南
swagger-codegen Eiffel 客户端中 mixedPropertiesAndAdditionalProperties 模型的生成与使用全解析
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考





