交换 css 字体时是否发出 js 事件?
Is a js event emitted when a css font is swapped?
我能否判断字体何时已成功(或以其他方式)加载,然后使用 JS 进行操作?
上下文
我正在使用 playwright 打印一系列文档。我目前正在加载这些字体 https://fonts.googleapis.com/css2?family=Raleway:wght@100;300;600&display=swap
,有时 waitUntil="networkidle"
会在字体加载之前完成 ½ 秒的等待,导致文档以后备字体打印。
参考资料
我读过 this: Controlling Font Performance with font-display and this: Navigating & waiting,并进行了大量搜索,但无济于事。
可能的解决方法
- 我可以将字体下载到我的计算机上,这样它就成为本地资产,但这意味着如果我以后改变了对字体的想法,就需要记住一个额外的步骤。这也使得在远程机器上做起来更难。
- 我可以添加一个 >4 秒的胖垫作为显式等待,但是如果 N=文档数量(每 100 个文档 6½)运行 时间会增加 4×N 秒
- 我可以写一个 service worker 来预缓存字体,然后发出一个事件,但这比它应得的要多得多,而且管理它的生命周期似乎是一个痛苦的未来。
有没有简单的方法?
是的,您可以使用 Font Face Observer 来执行此操作,它是一个小型的@font-face,用于监视字体的加载。这并不限制您使用任何类型的字体加载。
例如
var font = new FontFaceObserver('My Family', {
weight: 400
});
font.load().then(function () {
console.log('Font is available');
}, function () {
console.log('Font is not available');
});
如果您想了解更多信息,请查看 https://portalzine.de/dev/options-to-detect-when-a-font-face-has-been-loaded/
希望能回答您的问题。
christopher-holder's answer pointed me at that useful article from Portalzine中的link。我使用了他们第一个选项的技术,即
alert('Roboto loaded? ' + document.fonts.check('1em Roboto')); // false
document.fonts.ready.then(function () {
alert('All fonts in use by visible text have loaded.');
alert('Roboto loaded? ' + document.fonts.check('1em Roboto')); // true
});
document.fonts.onloadingdone = function (fontFaceSetEvent) {
alert('onloadingdone we have ' + fontFaceSetEvent.fontfaces.length + ' font faces loaded');
};
并使用 page.waitForFunction
将逻辑移动到 Playwright 脚本中,如下所示:
await page.goto(
"file:///" + path.resolve(htmlFilename),
(waitUntil = "networkidle")
);
await page.waitForFunction(() => document.fonts.check("1em Raleway"));
这会等待页面加载完成,并等待网络安静 ½ 秒,然后检查字体是否已加载。
FontFaceObserver 看起来不错,但是这种方法保留了编剧脚本中的打印逻辑并且不触及文档本身,感觉更干净。
这可能是腰带和牙套,我会在更彻底地测试后更新这个答案。
这是我用来重新调整滚动位置的一段 JS 代码,以针对 :target
scroll-margin
和不同于后备字体的网络字体进行调整:
if (location.hash)
{
var targetElement = document.getElementById(location.hash.substring(1));
if (targetElement && targetElement.scrollIntoView)
{
// scroll to correct position immediately
targetElement.scrollIntoView({block:"start", behavior:"auto"});
// Note that because the page might be rendered before
// web fonts are ready and web fonts may/will cause
// layout shift, we'll need to re-adjust the scroll
// position when fonts are ready:
try
{
var fontsReady = document.fonts.ready;
fontsReady.then(function ()
{
console.log('Font loading complete');
// process full event loop and re-adjust the scroll:
window.setTimeout(function ()
{
targetElement.scrollIntoView({block:"nearest", behavior:"smooth"});
}, 0);
});
}
catch (e)
{
console && console.error && console.error(e);
console && console.log && console.log("This browser doesn't support observing font loading, scroll position may be incorrect.");
}
}
}
根据您的用例和预期的事件时间,对 scrollIntoView()
的两次调用都可以使用 behavior:"auto"
或 behavior:"smooth"
。另请注意,用户可能已经在使用后备字体渲染内容和完成网络字体加载之间滚动了视口,因此您可能需要添加额外的代码来侦听滚动事件,并避免在用户已经滚动时换入网络字体时滚动任何内容到另一个位置。
我能否判断字体何时已成功(或以其他方式)加载,然后使用 JS 进行操作?
上下文
我正在使用 playwright 打印一系列文档。我目前正在加载这些字体 https://fonts.googleapis.com/css2?family=Raleway:wght@100;300;600&display=swap
,有时 waitUntil="networkidle"
会在字体加载之前完成 ½ 秒的等待,导致文档以后备字体打印。
参考资料
我读过 this: Controlling Font Performance with font-display and this: Navigating & waiting,并进行了大量搜索,但无济于事。
可能的解决方法
- 我可以将字体下载到我的计算机上,这样它就成为本地资产,但这意味着如果我以后改变了对字体的想法,就需要记住一个额外的步骤。这也使得在远程机器上做起来更难。
- 我可以添加一个 >4 秒的胖垫作为显式等待,但是如果 N=文档数量(每 100 个文档 6½)运行 时间会增加 4×N 秒
- 我可以写一个 service worker 来预缓存字体,然后发出一个事件,但这比它应得的要多得多,而且管理它的生命周期似乎是一个痛苦的未来。
有没有简单的方法?
是的,您可以使用 Font Face Observer 来执行此操作,它是一个小型的@font-face,用于监视字体的加载。这并不限制您使用任何类型的字体加载。
例如
var font = new FontFaceObserver('My Family', {
weight: 400
});
font.load().then(function () {
console.log('Font is available');
}, function () {
console.log('Font is not available');
});
如果您想了解更多信息,请查看 https://portalzine.de/dev/options-to-detect-when-a-font-face-has-been-loaded/
希望能回答您的问题。
christopher-holder's answer pointed me at that useful article from Portalzine中的link。我使用了他们第一个选项的技术,即
alert('Roboto loaded? ' + document.fonts.check('1em Roboto')); // false
document.fonts.ready.then(function () {
alert('All fonts in use by visible text have loaded.');
alert('Roboto loaded? ' + document.fonts.check('1em Roboto')); // true
});
document.fonts.onloadingdone = function (fontFaceSetEvent) {
alert('onloadingdone we have ' + fontFaceSetEvent.fontfaces.length + ' font faces loaded');
};
并使用 page.waitForFunction
将逻辑移动到 Playwright 脚本中,如下所示:
await page.goto(
"file:///" + path.resolve(htmlFilename),
(waitUntil = "networkidle")
);
await page.waitForFunction(() => document.fonts.check("1em Raleway"));
这会等待页面加载完成,并等待网络安静 ½ 秒,然后检查字体是否已加载。
FontFaceObserver 看起来不错,但是这种方法保留了编剧脚本中的打印逻辑并且不触及文档本身,感觉更干净。
这可能是腰带和牙套,我会在更彻底地测试后更新这个答案。
这是我用来重新调整滚动位置的一段 JS 代码,以针对 :target
scroll-margin
和不同于后备字体的网络字体进行调整:
if (location.hash)
{
var targetElement = document.getElementById(location.hash.substring(1));
if (targetElement && targetElement.scrollIntoView)
{
// scroll to correct position immediately
targetElement.scrollIntoView({block:"start", behavior:"auto"});
// Note that because the page might be rendered before
// web fonts are ready and web fonts may/will cause
// layout shift, we'll need to re-adjust the scroll
// position when fonts are ready:
try
{
var fontsReady = document.fonts.ready;
fontsReady.then(function ()
{
console.log('Font loading complete');
// process full event loop and re-adjust the scroll:
window.setTimeout(function ()
{
targetElement.scrollIntoView({block:"nearest", behavior:"smooth"});
}, 0);
});
}
catch (e)
{
console && console.error && console.error(e);
console && console.log && console.log("This browser doesn't support observing font loading, scroll position may be incorrect.");
}
}
}
根据您的用例和预期的事件时间,对 scrollIntoView()
的两次调用都可以使用 behavior:"auto"
或 behavior:"smooth"
。另请注意,用户可能已经在使用后备字体渲染内容和完成网络字体加载之间滚动了视口,因此您可能需要添加额外的代码来侦听滚动事件,并避免在用户已经滚动时换入网络字体时滚动任何内容到另一个位置。