跳到主要内容

font-family

2023年08月02日
柏拉文
越努力,越幸运

一、认识


二、语法


2.1 内置字体

2.2 自定义字体

  1. 下载对应字体至项目

  2. 通过 @font-face 声明自定义字体

    @font-face{
    font-family: "DejaVuSansMNerdFont";
    src: url("DejaVuSansMNerdFont.ttf");
    }
    @font-face{
    font-family: "HeavyDataNerdFont";
    src: url("HeavyDataNerdFont.ttf");
    }
  3. 通过 font-family 应用自定义字体

    .text1{
    font-family: "DejaVuSansMNerdFont";
    }

    .text2{
    font-family: "HeavyDataNerdFont";
    }
  4. 完整示例如下

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>自定义字体</title>
    <style>
    @font-face{
    font-family: "DejaVuSansMNerdFont";
    src: url("DejaVuSansMNerdFont.ttf");
    }
    @font-face{
    font-family: "HeavyDataNerdFont";
    src: url("HeavyDataNerdFont.ttf");
    }

    .text1{
    font-family: "DejaVuSansMNerdFont";
    }

    .text2{
    font-family: "HeavyDataNerdFont";
    }
    </style>
    </head>
    <body>
    <div class="text1">DejaVuSansMNerdFont 字体</div>
    <div class="text2">HeavyDataNerdFont 字体</div>
    </body>
    </html>

三、优化


3.1 动态加载字体文件 font-face

需求描述: 字体包体积巨大, 基本上都在几M左右。 所以,在以下场景需要考虑按需加载字体:

  • 场景一: 实时编辑一个 DOM 元素, 可以切换字体。如果直接将全部字体写入到样式文件中, IE 浏览器首先会下载全部注册声明的字体,即使未使用该字体。谷歌等浏览器实现了按需加载字体文件的功能。但是我们在使用 html2-canvas 或者 dom-to-image 第三方 DOMImage 的时候, 会下载完全部字体,然后再开始解析、转化, 增加了DOMImage的时间。

解决方案: 当需要加载字体时,向 DOM 添加 @font-face,动态加载字体。

实现如下:

const lazyLoadFontFamily = (fontFamily: string) => {
if (!fontFamily) {
return;
}
const documentStyle = document.createElement('style');
const fontFace = `
@font-face{
font-family: ${fontFamily};
src: url(${currentCdnUrl}custom-course-cover/fonts/${fontFamily}.ttf);
}
`;
documentStyle.appendChild(document.createTextNode(fontFace));
document.head.appendChild(documentStyle);
};

但是这里存在一个问题,由于请求接口需要一定的时间,文字会出现先空白一段时间后显示的现象。这种现象被称之为 FOIT (Flash Of Invisible Text)。我们需要寻找优化办法。 font-display 属性在 CSS 层面上提供了此类问题的解决方法。使用 font-display: swap 我们可以采用先使用系统默认字体,在中文字体下载完成后替换。

3.2 动态加载字体文件 FontFace

解决方案: 在 Javascript层面,浏览器也提供了 CSS Font Loading API 来操作字体。它在大部浏览器中已经得到了支持。通过 JS API 可以比较方便的控制页面的呈现。可以在字体加载前做些交互上的优化等

具体实现

const lazyLoadFontFamily = (fontFamily: string) => {
if (!fontFamily) {
return;
}

const newFont = new FontFace(fontFamily, `url("${currentCdnUrl}custom-course-cover/fonts/${fontFamily}.ttf")`);

document.fonts.add(newFont);
};

3.3 动态加载具体字体 font-face

解决方案: 当需要加载字体时,向 DOM 添加 @font-face,动态加载字体。

实现如下:

const lazyLoadFontFamily = (fontFamily: string) => {
if (!fontFamily) {
return;
}
const documentStyle = document.createElement('style');
const fontFace = `
@font-face{
font-family: ${fontname};
src: url("http://xxxx:8080/api/webfont?font=${fontname}&text=${encodeURIComponent(text)}`;

documentStyle.appendChild(document.createTextNode(fontFace));
document.head.appendChild(documentStyle);
};

通过 JavaScript 添加一个 CSS 样式。浏览器会自行解析并在下载完成字体后显示中文字体。

3.4 动态加载具体字体 FontFace

解决方案: 在 Javascript层面,浏览器也提供了 CSS Font Loading API 来操作字体。它在大部浏览器中已经得到了支持。通过 JS API 可以比较方便的控制页面的呈现。可以在字体加载前做些交互上的优化等

实现如下:

const lazyLoadFontFamily = (fontFamily: string) => {
if (!fontFamily) {
return;
}

const newFont = new FontFace(fontFamily, `url("http://xxxx:8080/fontmin?font=${fontname}&text=${encodeURIComponent(text)}")`);

document.fonts.add(newFont);
};

通过 JavaScript 添加一个 CSS 样式。浏览器会自行解析并在下载完成字体后显示中文字体。

参考方案