CSS – Font Family

前言

font-family 虽然只是一个 CSS 属性, 但是牵连许多东西, 所以独立一篇来讲.

网站一般上会使用 Google Fonts 作为 font-family, 下面会以一个 Google Fonts 为例子. 逐步解析它背后的 CSS 知识.

 

Pick a Google Font

到官网 fonts.google.com, 随便选一个 font 作为 font-family.

我选了 material 的 Roboto.

 

Select font-style and font-weight

知识点

1. 不是每个字体都有支持 Italic

2. 不是每个字体都支持 100 – 900 的 weight

3. 网站有使用到的才选择. 每一个 style 和 weight 都是一份字体文件, 下载越多越慢.

4. 常用的 weight 300, 400, 500, 700, Italic 尽量就别用了

作为示范, 我选了 normal 300, 400, 500, 700 和 Italic 400

右边点击 select, 就可以看见 selected 的 style 和 weight 了

 

Import CSS

它有 2 种 import 的 way.

第一是在 HTML 放 <link>

第二是在 CSS 放 @import, 我个人喜好是用这个

它其实就是一个去加载 CSS 的 URL

知识点

1. 以前是 css, 现在是 css2 版本不同了, Google 对字体做了一次改版, 如果你切换到 css 会拿到旧版本的字体

2. selected font-style

3. selcted font-weight

4. font-display 这个下面会详解讲它的作用.

如果有多个字体的话, 它的 URL 长这样

我加多了一个字体 Open Sans, 没有什么特别的. 只是 query param 多了 1 set family 而已 (相同 query param key 不常见, 但其实是符合规范的. 题外话: ASP.NET Core 获取 same query param key)

 

Set font-family Style

下方有声明如何使用在 Style

sans-serif 是 Roboto 的 fallback 字体.

效果

 

Import 的 CSS 做了什么?

上面有一个关键就是 Import CSS, 它做了啥?

用 DevTools 可以看到, 它加载了一个 CSS Style, 里面有 @font-face

 

@font-face

@font-face 是 CSS 语法. 用来 define 一个字体. 来看看它的属性.

@font-face {
  font-family: 'Roboto';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1Mu51xFIzIFKw.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

font-family, style, weight 就不多说了.

src 

字体文件 URL. 之前在 W3Schools 学习笔记 (3) – CSS Web Fonts 中有提过.

字体要渲染需要 TTF/OTF, WOFF 或者 WOFF2 文件.

所以, @font-face 只是定义了加载路径, 游览器会依据这个路径再去加载字体文件, 才能渲染.

另外, Google Fonts 是可以 self host 的哦, 通过 google-webfonts-helper 下载字体, 或者到官网下载 (but 官网的是 TTF, helper 是 WOFF2), 然后把 .woff2 或 .ttf 文件放到自己 server, src 改成 link to 自己 server 路径就可以了.

font-display

参考:

页面字体闪一下?这两个标准能帮到你

CSS-Tricks – font-display

它有好几个值

auto: 依据游览器行为, 一般是 block

block: 上面说了游览器需要加载 .woff 文件, 这段期间字体要如何展现呢? 

block 就是不显示. 直接给一个白色, 完全看不到字, 直到字体下载完成渲染后才显示. 这个体验叫 FOIT (Flash Of Invisible Text), 很少人这样做的, 体验不好

swap: 在等待加载的时候, 先显示 fallback 字体, 等加载完成才显示最终字体. 这个体验叫 FOUT (Flash Of Unstyled Text), 大部分人都这样做 (虽然体验也不是 100% 的好)

fallback: block 和 swap 的折中方案, 会先 block 100ms 左右, 然后 3秒 swap, 如果 3 秒后还没有加载成功, 那么就一直用 fallback 的. 考虑到 3 秒后用户已经开始阅读内容了, 这时切换字体会很明显跳一下, 体验扣很多分

optional: 和 fallback 类似. 只是把权力交给游览器依据下载速度决定是否去加载字体.

block, swap, fallback, optional 可以理解为你多在意自定义字体. block 就是一定要用自定义字体, 其它的连看都不可以. swap 就是可以先看 fallback 但最后一定要看到自定义

fallback 就不一定要看到自定义, 加载快才看. optional 顾名思义, 更加不注重了. 大部分人都会用 swap.

unicode-range 没有认真研究. 从 Google Fonts 的 @font-face 可以看到, 同一个 family, style, weight 会有很多版本的 unicode-range.

提醒:

不同 font-family, 不同 style, 不同 weight, 不同 unicode 都需要新的一个 @font-face 哦. 所以 @font-face 会有很多很多的.

 

CSS Font Loading API

参考:

stackoverflow – How to be notified once a web font has loaded

Medium – Getting started with CSS Font Loading

上面说到, @font-face 定义了 .woff2 的加载路径, 然后游览器去加载文件后渲染.

font-display swap 会先显示 fallback 的字体, 然后切换, 所以字体的 size 会改变.

如果我们依赖这个字体的 width 怎么办呢? 虽然可以用 ResizeObserver 监听, 但它不是最好的. 更好的是用 document.fonts

document.fonts 是一个 iterable 对象. 它记入了所有 @font-face 的内容.

for (const font of document.fonts) {
  console.log("font", font);
}

遍历后可以看到所以 @font-face 定义的字体

下面 2 个监听方式

document.fonts.ready.then(() => {
  console.log("all loaded");
});

[...document.fonts][0].loaded.then(() => {
  console.log("specify font loaded");
});

第一个是监听所有 font 加载完毕

第二个是指定某一个 font 加载完毕

JS 动态加载 font-face

上面都是靠 CSS @font-face 去加载的. JavaScript 也是有 API 可以动态加载 font 的哦.

注释 CSS

/*
  @font-face {
    font-family: "Roboto";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxK.woff2)
      format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
      U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
      U+FEFF, U+FFFD;
  }
*/

JavaScript

document.querySelector("button")!.addEventListener("click", () => {
  // define
  const robotoFontFace = new FontFace(
    "Roboto",
    `url(https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxK.woff2)
  format("woff2")`,
    {
      display: "swap",
      style: "normal",
      weight: "400",
      unicodeRange: `U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
      U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
      U+FEFF, U+FFFD`,
    }
  );

  // load
  robotoFontFace.load().then(() => {
    // add to document.fonts
    document.fonts.add(robotoFontFace);

    // set style
    document.querySelector("h1")!.style.fontFamily = `Roboto`;
  });
});

new FontFace 类似 CSS 的 @font-face. 照搬而已.

定义好 FontFace 把它添加到 document.fonts 里面去. 然后就可以使用了.

我上面调用 load 只是一个示范而已. 其实只要添加进了 document.fonts 它就会自动去加载了.

 

和 font-family 有关的文章

Figma 学习笔记 – Text

webpack – postcss-font-magician

 

总结

1. font-family 需要 .woff2 文件 (.woff2 文件就是 font 的设计文档, 有些是版权的哦, 不可以随便用)

2. CSS Style @font-face 只定义了加载路径

3. 游览器加载 font 时, font-display 控制体验

4. JS 也有 API 可以设置 font-face 和监听 font rendered.

 

中文 font

参考:

Web 开发中文字体指南

Github – font-family: -apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif

CSS - Tracks – System Font Stack

[前端基础]font-family 详解

英文字体有非常多的选择, 电脑没有可以去下载一个就搞定了.

但中文就不行了. 中文 file 太大了, 随便一个就可能要 10mb.

所以网站要支持中文, 就只能用电脑已有的字体.

Safe fonts

下面是英文的 safe fonts

那中文呢...不好意思...没有通用的.

不同的 OS 用的中文字体是不同的, 而我们需要兼顾 4 个 OS, Windows, macOS, IOS, Android.

font-family

system-ui 这个是所有 OS 通用的字体 (比较新, 如果要兼容一些老旧设备需要配上下面几个)

-apple-system 这个是苹果机 IOS, macOS 的字体.

BlinkMacSystemFont 这个是早年的 macOS Chrome 的字体

Segoe UI for Windows

Noto Sans for Android (在 Android. Noto for chinese, Roboto for english)

full version

所以目前最常见的方案是 

先放一个 english pretty 字体. 

然后跟着下面这句

my-pretty-font,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"

这样就可以保证中英文都支持美美了.

各大网站参考

Boostrap

system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"

TailwindCSS

Inter var,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji

博客园

"PingFang SC","Microsoft YaHei","Helvetica Neue","Helvetica","Arial",sans-serif;

Tesla

"Gotham SSm", "PingFang SC", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif

Apple

"SF Pro SC", "HanHei SC", "SF Pro Text", "Myriad Set Pro", "SF Pro Icons", "Apple Legacy Chevron", "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif

Microsoft

"Segoe UI",SegoeUI,"Helvetica Neue",Helvetica,Arial,sans-serif

Github

-apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"

Medium

source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif

可以看到 Boostrap, TailwindCSS, Github 是比较完整的. 像 Microsoft 根本不鸟 IOS, macOS, Apple 也没放 Segoe UI.

 

posted @ 2022-06-11 00:35  兴杰  阅读(1138)  评论(0编辑  收藏  举报