这一期中我们将围绕着Web中的font来展开。在现代Web中除了能使用font-family属性给Web应用指定字体之外,还有其他一些用于字体的特性,比如@font-face可以加载非系统的字体,字体变体属性font-variation-*让Web上排版和印刷上排版之间的差距在逐渐拉小,font-display属性来决定非系统方面字体的加载策略,提高性性能,font-palette用来选择字体配色,@font-palette-values自定义字体配色等。如果你感兴趣的话,请继续往下阅读。

@font-face的使用

@font-face {
font-family: 'NeuesBauenDemo';
src: url('../fonts/neues_bauen_demo-webfont.eot');
src: url('../fonts/neues_bauen_demo-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/neues_bauen_demo-webfont.woff') format('woff'),
url('../fonts/neues_bauen_demo-webfont.ttf') format('truetype'),
url('../fonts/neues_bauen_demo-webfont.svg#NeuesBauenDemo') format('svg');
font-weight: normal;
font-style: normal;
}
.neuesDemo {
font-family: 'NeuesBauenDemo'
}

比如上面的示例,可以让Web上的字体更具艺术范:

@font-face除了能让Web开发者使用第三方字体之外,还有另外一个优势,而且在Web中运用也非常的常见,即字体图标。比如Font Awesome就是一个非常受欢迎的用字体制作的图标库。

@font-face {
font-family: 'FontAwesome';
src: url('font/fontawesome-webfont.eot');
src: url('font/fontawesome-webfont.eot?#iefix') format('embedded-opentype'), url('../font/fontawesome-webfont.woff') format('woff'), url('../font/fontawesome-webfont.ttf') format('truetype'), url('../font/fontawesome-webfont.svgz#FontAwesomeRegular') format('svg'), url('../font/fontawesome-webfont.svg#FontAwesomeRegular') format('svg');
font-weight: normal;
font-style: normal;
}
<div class="icon-glass"></div>

使用也非常的方便。而且在现使用Font Awesome只需要调用相关的资源链接,需使用的时候指定相应的图标类名即可:

上面看到的字体都是现成的,如果你是一名设计师或者说你懂得字体的设计。那么你就可以在任何Web页面或Web应用上使用你自己设计的字体。这样一来,是不是非常有成就感。同样的原理,还可以设计一些SVG矢量图标,借助IcoMoon Web App将图标生成Web可用的Web字体:

如果你对Web中字体图标相关的东西感兴趣的话,还可以阅读下面相关文章:

@font-face带来很多优势,但大多人一般只会聊自定义的Web字体如何定义,但是没有过多的人考虑其实际性能:

特别是网络环境不好或弱网情况之下,可能访问带有Web字体的应用会对用户带来一些不好的体验。比如下面这个录展所示的效果:

基本的@font-face使用方法会至使用户加载字体受到阻塞。不过庆幸的是,我们可以找到一些技术方案来改善字体加载性能,让使用Webp字体的性能更好,加载字体更流畅。后面我们会聊到这些相关的技术。

如何使用第三方字体

<!-- HTML中通过link标签引用 -->
<link href="https://fonts.googleapis.com/css?family=Gloria+Hallelujah" rel="stylesheet">

或者:

/* 在CSS中通过@import引用 */
@import url('//fonts.googleapis.com/css?family=Lato:400,400italic,700|Sansita+One');

打开字体文件,你会发现代码如下:

/* latin-ext */
@font-face {
font-family: 'Lato';
font-style: italic;
font-weight: 400;
src: local('Lato Italic'), local('Lato-Italic'), url(https://fonts.gstatic.com/s/lato/v15/S6u8w4BMUTPHjxsAUi-qNiXg7eU0.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* 部分代码略去 */

可以看到,依旧离不开@font-face这个属性。当然里面还有一些其他的设置,比如unicode-range

简单地说,上面的示例使用了Google Font,而且使用Google Font的人非常的多。在Google Fonts上有很多字体能提供大家选用:

其实按这样的原理,我们也可以把自己的图标提交到线上,使用CDN地址。

使用Google字体还是有一些小技巧,这些技巧有助于我们搞高字体加载的性能。后面会聊一些这些技巧。如果你的字体也放在CDN上,也可以按类似的方案来做处理。如果感兴趣话,敬请后面的内容。

Web中的中文字体

碰到这样的场景大部分解决方案,要么是使用系统默认字体,要么是使用图片来替换。或许你会问:

既然@font-face这么牛逼,为什么中文艺术字体不用该特性呢?

原因非常简单,对于英文而言,它只有26字母,一张ASCII码上128个字符集,体量较小,设计成本较小。但对于中文而言,单单GB2313编码的中文字字符就达到7445个,体量较大,设计成本较大。这就是中文相比于英文不太好设计的原因之一,如果要设计出这么一套中文字体(带艺术性,个性化字体),除了设计成本和难度较大之外,就算是设计出来,字体体积也非常的大,面对这么大的字体文件,要是运用于Web上,也不是件易事。最起码要面对字体的加载,性能的优化等问题。

不过并不是没有任何方案可解,在社区中也有相应的字体裁剪工具,比如:

就算是有了这些工具,我们也无法大面积的在Web上使用特殊的中文字体。而在中文Web应用程序中,使用这种艺术字体的场景也不是全站都是,大部分会出现在标题、Banner等场景。而这样的场景下所需的字体数量有限的,这样我们就可以借助上面的两个工具对字体进行裁剪,生成一个只包含特定字符的小字体文件。这样就达到了减少字体文件的目标。

有关于这方面的详细介绍可以阅读下面几篇文章:

字体加载性能优化

下面简单的来了解一下@Danny Cooper在文章中给我们介绍哪些技术手段能对字体方面做相关的优化。

不管是使用的Google Fonts还是其他地方提供的字体。可以说每种字体在Web浏览器中显示之前都需要先下载。通过正确的设置,额外的加载时间并不明显。但是,如果出现错误,用户可能需要等待一定的时候才能显示。接下来,作者拿Google Fonts为例,阐述了如何对字体做相关的性能优化。

Google Fonts已经做过相应的优化

如果我们从API请求相同的字体变体(Font variant)就会得到这个文件,只有11kb。是不是很神奇。那是因为,当浏览器向API发出相应的请求时,Google首先会检查浏览器支持哪些文件类型。比如最新版本的Chrome浏览器和大多数的浏览器一样,也支持WOFF2,所以字体是以高度压缩的格式提供给我们的。

不同的浏览器会获取不同的字体格式。

最为强大的是,Google Fonts 为 每种字体维护了30多个优化的字体变体,并自动检查和交付每种平台和浏览器的最佳变体。@Ilya Grigorik在这方面做过深入的讨论,详细的可以阅读《网页字体优化》一文。

网页字体是一个字形集合,而每个字形是描述字母或符号的矢量形状。 因此,特定字体文件的大小由两个简单变量决定:每个字形矢量路径的复杂程度和特定字体中字形的数量

浏览器缓存

由于Google Fonts的普遍性,浏览器并不总是需要下载完整的安体文件。例如,使用了Mija这样的一个字体,如果你的浏览器首次看到该字体,在需要显示之前会下载该字体,但下次再重新访问该网站时使用之个字体,浏览器将会使用缓存版本。

Google Fonts浏览器缓存被设置为一年后过期,除非缓存被提前清除。

进一步优化的可能

字体库做相应的限制

在页面中不要使用超过两种字体,一种用于标题,另一种用于内容。

使用正确的字体大小、重量和颜色,即使只有一种字体,在性能上也有较好的优化。

排队变体

这对于可能需要所有12种变体的高级用例来说是非常好的,但是对于一个普通的网站,意味着下载所有12种变体,就过于浪费,因为你可能只会用到34种变体。例如,Roboto字体系列的重量大约为144kb。但是,如果你只使用常规的,常规的斜体和粗体等,那么这个字体的重量就可以下降到大约36kb,相当于节约了75%

一般情况下,加载Google Fonts的默认代码如下:

<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">

这样做,只是加载了常规400Regular 400)版本。这意味着字体集中的其他版本,比如LightBoldItalic将不会正确的显示。如果要改变这个现象,即 要加载所有字体变体,可以在href中的URL显式指定字体变体的权重,如下所示:

<link href="https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,500,500i,700,700i,900,900i" rel="stylesheet">

前面也提到过了,很少网站会使用所有字体的变体,从100900,而实际使用中,最佳的方式是指定你可能需要的字体变体权重,比如:

<link href="https://fonts.googleapis.com/css?family=Roboto:400,400i,600" rel="stylesheet">

这种方式,在使用多个字体的时候更显得重要。比如,如果使用Lato作为Web中的标题,它可能只会请求粗体(可能还会有粗体斜体):

<link href="https://fonts.googleapis.com/css?family=Lato:700,700i" rel="stylesheet">

减少http请求

<!-- 优化前的方式 -->
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,400i,600" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<!-- 优化后的方式 -->
<link href="https://fonts.googleapis.com/css?family=Roboto|Open+Sans:400,400i,600" rel="stylesheet">

资源提示

<link rel="prefetch" href="/style.css" as="style" />
<link rel="preload" href="/style.css" as="style" />
<link rel="preconnect" href="https://example.com" />
<link rel="dns-prefetch" href="https://example.com" />
<link rel="prerender" href="https://example.com/about.html" />

其中dns-prefetchpreconnect对于字体加载方面的优化有很大的作用。

dns-prefetch允许浏览器在页面开始加载时立即启动和Google Fonts API(fonts.googleapis.com)的连接。这意味着当浏览器准备发出请求时,一些工作已经完成了。要实现谷歌字体的dns-prefetch,只需要在<head>标签中添加像下面这样的一行代码即可:

<link rel="dns-prefetch" href="//fonts.googleapis.com">

另外,谷歌字体的嵌入代码看上去好像只发出一个单一的HTTP请求:

<link href="https://fonts.googleapis.com/css?family=Roboto:400,400i,700" rel="stylesheet">

事实上并非如此如果我们访问https://fonts.googleapis.com这个URL,它并不只发出一个HTTP请求,其实他实际上发出了多个请求。

/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local('Roboto Italic'), local('Roboto-Italic'), url(https://fonts.gstatic.com/s/roboto/v19/KFOkCnqEu92Fr1Mu51xFIzIXKMnyrYk.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local('Roboto Italic'), local('Roboto-Italic'), url(https://fonts.gstatic.com/s/roboto/v19/KFOkCnqEu92Fr1Mu51xMIzIXKMnyrYk.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local('Roboto Italic'), local('Roboto-Italic'), url(https://fonts.gstatic.com/s/roboto/v19/KFOkCnqEu92Fr1Mu51xEIzIXKMnyrYk.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local('Roboto Italic'), local('Roboto-Italic'), url(https://fonts.gstatic.com/s/roboto/v19/KFOkCnqEu92Fr1Mu51xLIzIXKMnyrYk.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local('Roboto Italic'), local('Roboto-Italic'), url(https://fonts.gstatic.com/s/roboto/v19/KFOkCnqEu92Fr1Mu51xHIzIXKMnyrYk.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local('Roboto Italic'), local('Roboto-Italic'), url(https://fonts.gstatic.com/s/roboto/v19/KFOkCnqEu92Fr1Mu51xGIzIXKMnyrYk.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local('Roboto Italic'), local('Roboto-Italic'), url(https://fonts.gstatic.com/s/roboto/v19/KFOkCnqEu92Fr1Mu51xIIzIXKMny.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;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu72xKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu5mxKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu7mxKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu4WxKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu7WxKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu7GxKKTU1Kvnz.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.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;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmWUlfCRc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmWUlfABc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmWUlfCBc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmWUlfBxc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmWUlfCxc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmWUlfChc4AMP6lbBP.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmWUlfBBc4AMP6lQ.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;
}

如果在<link>标签中指定rel="preconnect"时,这些附加的请求的问题是,直到第一个对https://fonts.googleapis.com/css的请求完成之后,浏览器才会开始处理这些请求。

也可以说preconnectprefetch的增强版。它是在浏览器将要加载的特定URL上设置它。它不仅执行DNS查找,还完成了TSL协商和TCP握手。

<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>

仅仅添加这一行代码就可以将页面加载时间减少100ms

如果你对Resource Hints相关的技术感兴趣的话,还可以阅读下面相关的教程进行扩展:

本地字体

另外,谷歌字体还提供一个服务,允许你选择要使用的字体,然后提供所需的文件和CSS。

font-display

@font-face {
font-family: 'Roboto';
src: local('Roboto Thin Italic'),
url(https://fonts.gstatic.com/s/roboto/v19/KFOiCnqEu92Fr1Mu51QrEz0dL-vwnYh2eg.woff2)
format('woff2');
font-display: swap;
}

如果引用谷歌在线的字体,还可以这样使用:

<link href="https://fonts.googleapis.com/css?family=Noto+Sans+HK&display=swap" rel="stylesheet" >

hrefURL地址上配合font-display一起使用&display=swap

font-display它还能实现类似于Font Loading APIBram Stein's Font Face Observer这种第三方脚本实现的功能。

用一张简单的图来描述font-display属性对浏览器加载字体的相关影响:

特别声明,上图来自于@monica的《Font-display》一文。

有关于font-display属性更多的相关介绍可以阅读:

使用text参数

https://fonts.googleapis.com/css?family=Roboto&text=CompanyName

当然,这种技术非常具体,只有少数实际应用。然而,如果你可以使用它,它可以减少字体的重量高达90%。另外,使用text的参数时,默认情况下只加载normal的字体权重(font-weight)。如果需要使用另外的一个权重,需要在URL中显式的指定它:

https://fonts.googleapis.com/css?family=Roboto:700&text=CompanyName

这几点是@Danny Cooper针对于Google Fonts API做的一些性能优化。其实文章中提到的这些技术方案能否实用于其他的第三方字体库有待于考量,但是对于font-display属性而言,他可以适用于任何一个加载字体的地方。

其他字体加载的优化

CSS字体加载API

如果你担心浏览器是否支持该API,可以先对其做相应的判断:

;(function () {
if (!('fonts' in document)) return;
})();

如果不支持,那程序会直接return掉,释放程序。该方法使用promise在加载字体后运行函数。该函数将会传递font-sizename作为参数,并使用.then()设置函数,该函数将在加载字体后运行。比如下面这个示例:

;(function () {
if (!('fonts' in document)) return;
document.fonts.load('1em PT Serif').then(function () {
document.documentElement.className += ' fonts-loaded';
});
})();

在函数中,我们将在html元素中添加.font-load类,它将激活自定义字体。

另外该方法还可以为字体在浏览器中设置一个缓存的期间:

;(function () {
if (!('fonts' in document)) return;
document.fonts.load('1em PT Serif').then(function () {
var expires = new Date(+new Date() + (7 * 24 * 60 * 60 * 1000)).toUTCString();
document.cookie = 'fontsLoaded=true; expires=' + expires;
document.documentElement.className += ' fonts-loaded';
});
})();

在页面加载时,如果cookie存在,将立即添加.font-load类到html元素中并结束程序。

注意,load()方法仅适用于现代浏览器,但在Edge和IE支持。如果你想使用该方法来加载自定义字体的话,可以考虑将FontFaceSet.load()fontFaceObserver结合起来:

;(function () {    // Native behavior
if ('fonts' in document) {
document.fonts.load('1em PT Serif').then(function () {
var expires = new Date(+new Date() + (7 * 24 * 60 * 60 * 1000)).toUTCString();
document.cookie = 'fontsLoaded=true; expires=' + expires;
document.documentElement.className += ' fonts-loaded';
});
}
// Fallback for IE/Edge
else {
// Use fontFaceObserver
}
})();

如果你对这方面的知识感兴趣的话,还可以阅读下面相关文章:

字体加载策略

最近,@zachleat在他的新博客中以CSS-Tricks网站为例,介绍了CSS-Tricks中是如何使用CSS相关的技巧为开发提供了比较健壮的字体加载策略。

文章中提到的一些策略(或者说技术手段)和@Danny Cooper文章中提到的有点类似。比如<link>标签中rel指相应的属性(如preload)、CSS的font-display,CSS字体加载API(如FontFace)等。文章中详细讨论了如何为两个阶段加载确定不同特性的优先级。但是实现起来难度并不大,代码非常简单。

首先,在第一阶能做的事情。

预加载HTML,可以使用link标签的rel属性来指定加载姿势:

<link rel="preload" href="Rubik-Bold-kern-latin.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="Rubik-Regular-kern-latin.woff2" as="font" type="font/woff2" crossorigin>

另外使用到@font-face的CSS内联到页面中(放置在</head>)中:

@font-face {
font-family: Rubik;
src: url(Rubik-Bold-kern-latin.woff2) format("woff2"),
url(Rubik-Bold-kern-latin.woff) format("woff");
font-weight: 700;
font-display: swap;
}
@font-face {
font-family: Rubik;
src: url(Rubik-Regular--kern-latin.woff2) format("woff2"),
url(Rubik-Regular-kern-latin.woff) format("woff");
font-weight: 400;
font-display: swap;
}

第二阶段就是借助JavaScript来做相关的优化,这里指的就是CSS字体加载相关的API。你可以把这段脚本放到任何你想放的地方。也可以内联到<head>中:

if( "fonts" in document ) {
var regular = new FontFace("Rubik", "url(Rubik-Regular-hint-all.woff2) format('woff2'), url(Rubik-Regular-hint-all.woff) format('woff')");
var bold = new FontFace("Rubik", "url(Rubik-Bold-hint-all.woff2) format('woff2'), url(Rubik-Bold-hint-all.woff) format('woff')", { weight: "700" });
Promise.all([ bold.load(), regular.load() ]).then(function(fonts) {
fonts.forEach(function(font) {
document.fonts.add(font);
});
});
}

如果你有更重要的资源需要加载的话,建议到这段脚本之前,以免被阻塞。前面也提到过了,CSS字体加载相关的API不是所有浏览器都支持,如果你使用了该方面的API来对字体加载做相应的优化的话,那么还可以考虑像下面这样的方式为不支持CSS字体加载的API提供相应的降级方案:

if(!("fonts" in document) && "querySelector" in document) {
// Awkwardly dump the second stage @font-face blocks in the head
var style = document.createElement("style");
// Note: Edge supports WOFF2
style.innerHTML = "@font-face { font-family: Rubik; src: url(/rubik/Rubik-Regular-hint-all.woff2) format('woff2'), url(/rubik/Rubik-Regular-hint-all.woff) format('woff'); } @font-face { font-family: Rubik; font-weight: 700; src: url(/rubik/Rubik-Bold-hint-all.woff2) format('woff2'), url(/rubik/Rubik-Bold-hint-all.woff) format('woff'); }";
document.querySelector("head").appendChild(style);
}

字全加载优化其他资料

CSS 字体新玩法之彩色字体

如果说,使用CSS相关的特性能实现上图这样的彩色字体效果,会不会感到非常的惊讶和好奇。是的,不会错的,在CSS Fonts Module Level 4工作草案中提供了一些新特性,即为Color Font提供了相应的描述。

选择字体配色:font-palette

  • normal:浏览器尽可能地将该字体当作非彩色字体进行渲染,并选择一个最适合阅读的配色方案。浏览器在做决策时还可能将当前设定的字体颜色color加入决策条件中。还有可能自动生成一组未内置在字体中的配色方案进行渲染。
  • light:一些彩色字体在其元数据中标明某个配色方案适用于亮色(接近于白色)背景中。使用此数值,浏览器将会直接使用标记了该特性的首个配色方案进行渲染。如果字体文件格式无元数据或时元数据中未标记相应的配色方案,那么此时该数值的行为与 normal 相同
  • dark:正好与light 相反
  • 自定义:上面我们介绍了三种基本的配色选择,那么如果要使用其他的配色方案或是要自定义,我们将要借助接下来介绍的@font-palette-values的帮助。

自定义字体配色:@font-palette-values

它的基本定义规则是@font-palette-values namename 即为本配色规则的自定义规则名称。

如果你对彩色字体感兴趣的话,可以阅读早前整理的一文章

字体变体font-variation-*

  • font-variant-ligatures
  • font-variant-caps
  • font-variant-numeric
  • font-variant-alternates
  • font-variant-east-asian

这里不对字体变体做过多的阐述,如果你对这面感兴趣,可以阅读《字体变体font-variation-*》一文。这里给大家提供一个案例,让大家有一个更形象的体感:

CSS中的镜像

在制作窗棂时使用到了CSS的-webkit-box-reflect属性。印象中最早接触该属性的时候大约是在2014年的时候,就尝试着使用了这个属性来实现一些倒影或镜像的效果

而在CSS中实现镜像效果的技术方案不仅局限于-webkit-box-reflect属性。接下来,简单的聊聊CSS中的镜像。

CSS Transform实现镜像

使用上面提到的方法,可以很容易的实现水平和垂直方向的镜像效果

-webkit-box-reflect实现镜像

  • none:此值为-webkit-box-reflect默认值,表示无倒影效果;
  • <direction>:此值表示-webkit-box-reflect生成倒影的方向,主要包括以下几个值:above生成的倒影在对象(原图)的上方;below生成的倒影在对象(原图)的下方;left生成的倒影在对象(原图)的左侧;right生成的倒影在对象(原图)的右侧;
  • <offset>:用来设置生成倒影与对象(原图)之间的间距,其取值可以是固定的像素值,也可以是百分比值,如:使用长度值来设置生成的倒影与原图之间的间距,只要是CSS中的长度单位都可以,此值可以使用负值;使用百分比来设置生成的倒影与原图之间的间距,此值也可以使用负值
  • <mask-box-image>:用来设置倒影的遮罩效果,可以是背景图片,也可以是渐变生成的背景图像。

比如@袁川 老师在教程中向大家演示的案例,就是使用该特性制作的一个中国式窗棂效果

CSS element()函数

使用该函数配合transform可以像-webkit-box-reflect一样实现镜像效果:

在CSS中,不管是-webkit-box-reflect,还是transfrom: scaleX(-1)(或transform: scaleY(-1)),甚至element()函数之类的,结合CSS Making相关的特性或者CSS渐变相关的特性会让镜像效果更佳。比如 @ANA TUDOR在她的教程《The State of CSS Reflections》(译文)中向大家演示的案例

如果你对CSS中实现镜像相的技术感兴趣的话,还可以阅读下面相关教程:

小结

既然使用@font-face特性,都将面临字体的加载,不管是线上(从CDN加载字体)还是加载本地字体,都要考虑怎么做字体加载。所以这一期中,大部分篇幅和大家一起聊聊怎么来优化字体加载,提高页面性能,从而改善用户体验。

最后再向大家展示了CSS另一方面的能力,即,怎么使用CSS的transform-webkit-box-reflectelement()等来实现镜像效果。最后,希望这一期中讨论的东西,大家会喜欢。如果您在这方面有相关的经验,或有较好的建议,欢迎在下面的评论中与我们一起讨论。

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
原文: https://www.w3cplus.com/web/web-tips-12.html © w3cplus.com

“大漠”,w3cplus.com 创始人。前端码畜,专业搬运工

“大漠”,w3cplus.com 创始人。前端码畜,专业搬运工