JSX 中异步加载字体样式表

之前在 博客网站性能优化 上调整过 webfont 加载相关逻辑,取得不错的效果。现在打算在 Publish Obsidian Vault 网页上用更加 2025 年现代的方式再实践一遍。

互联网上还流传有两种异步加载 CSS 的写法,使用 preload 和 使用 media ,实测它们在 Lighthouse 上的的性能一致。

<link rel="preload" as="style" crossorigin
  href="https://cdn.jsdelivr.net/npm/misans-vf@1.0.0/lib/MiSans.min.css" 
  onload="this.onload=null;this.rel='stylesheet'" />
 
<link rel="stylesheet" media="print" crossorigin
  href="https://cdn.jsdelivr.net/npm/misans-vf@1.0.0/lib/MiSans.min.css"
  onload="this.removeAttribute('onload');this.media='all'" />

The Simplest Way to Load CSS Asynchronously | Can’t rel=preload do this too? | Filament Group, Inc. 有解释,使用 media 的兼容性更好(但现代浏览器已经完全支持了);preload 的优先级特别高。对于字体文件,倒是希望降低优先级,所以这里我用 media 的特性。

如果只简单地将 onload=null 并不能从 HTML 中把 onload 属性去掉,所以这里我用 this.removeAttribute('onload')

使用 preload 改造为异步加载,但是在 JSX 中做有些麻烦,不应该用 React 的 onLoad,而是 HTML 原生的 onload,得动态注入

/** 往 JSX 中添加 onload 属性 */
function preloadStylesheetOnloadFn() {
  return { 'onload': "this.removeAttribute('onload');this.media='all'" };
}
 
function misansFontStylesheet(): JSX.Element {
  return (
    <>
      <link rel="stylesheet" media="print" crossorigin="anonymous"
        {...preloadStylesheetOnloadFn()}
        href="https://registry.npmmirror.com/misans/latest/files/lib/Normal/MiSans-Medium.min.css" />
      <link rel="stylesheet" media="print" crossorigin="anonymous"
        {...preloadStylesheetOnloadFn()}
        href="https://registry.npmmirror.com/misans/latest/files/lib/Normal/MiSans-Bold.min.css" />
    </>
  )
}

以及如果都使用同一个 CDN,同时下载很多 WOFF2 文件会拖慢同一个 CDN 的其他资源下载队列。
经过 NPM 镜像选择 测速,选择 释放字体自由 - ZeoSeven Fonts (ZSFT)npmmirror 镜像站 作为 CDN。

然后对于 MiSans,npmmirror 的速度已经比 jsdelivr 快了一倍,但切换到小米自己的 CDN 那就是天翻地覆的速度 🙂 作为小米车主,偷偷地盗个链