Web技巧(12)

栏目: CSS · 发布时间: 5年前

内容简介:这一期中我们将围绕着Web中的现代Web的开发,除了追求技术上的完善之外,有些开发者是设计出身,很多时候也追求艺术上的更好展现。特别是对于Web字体来说,受限于系统可用的字体非常的有限。但随着比如上面的示例,可以让Web上的字体更具艺术范:

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

@font-face的使用

现代Web的开发,除了追求技术上的完善之外,有些开发者是设计出身,很多时候也追求艺术上的更好展现。特别是对于Web字体来说,受限于系统可用的字体非常的有限。但随着 @font-face 的出现 ,Web开发者可以使用第三方(非系统内置)的字体,比如:

@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上的字体更具艺术范:

Web技巧(12)

@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技巧(12)

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

Web技巧(12)

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

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

Web技巧(12)

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

Web技巧(12)

基本的 @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 上有很多字体能提供大家选用:

Web技巧(12)

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

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

Web中的中文字体

这里所说的Web中的中文字体,并不是我们系统常见的字体,比如“宋体”、“楷体”、”萍方“和”微软雅黑“等。拿个示例来说吧,在UI还原中,你肯定碰到带有艺术字体的设计稿:

Web技巧(12)

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

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

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

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

Web技巧(12)

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

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

字体加载性能优化

前面提到过,使用 @font-face 使用第三方字体的时候受限于字体的大小,网络的影响等,对用户的体验是会有相应的影响。除了降低字体包的大小之外还有一些别的优化方式。比如@Danny Cooper在他的最新博客中就聊到了如何 优化Google Fonts性能 。在这篇文章中提到的一些优化方案其实都适合使用 @font-face 的任何地方。

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

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

Google Fonts已经做过相应的优化

Google Fonts API不仅仅向我们提供字体文件,它还有一个更大的优势,就是会 执行智能检查,以查看如何以最优化的格式交付文件 。 比如 Roboto 字体,Github告诉我们,常规版的字体体积大约为 168kb

Web技巧(12)

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

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

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

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

浏览器缓存

Google Fonts的另一个内置优化是 浏览器缓存

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

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

进一步优化的可能

虽然谷歌在优化字体文件的交付方面投入了大量的精力,但是仍然可以在实际使用中进行一些更多的优化,以减少对页面加载时间的影响。

字体库做相应的限制

最简单的优化注是使用更少的字体库。每种字体的页面重量加起来可能达到 400kb ,再乘以几个不同的字体族,您的字体的重量就会突然超过整个页面的重量。@Danny Cooper在文章中建议:

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

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

排队变体

Google Fonts质量是出了名的,而Google为了让字体具有较高的质量标准,请多字体都包含了可用的字体权重( font-weight ):

权重关键词 权重对应的值 权重关键词 权重对应的值 权重关键词 权重对应的值 权重关键词 权重对应的值
Thin 100 Thin Italic 100i Light 300 Light Italic 300i
Regular 400 Regular Italic 400i Medium 600 Medium Italic 600i
Bold 700 Bold Italic 700i Black 800 Black Italic 800i

这对于可能需要所有 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请求

不管是使用Google Fonts(如果没有下载到本地)或者使用其他CDN上的线上字体库,都会需要相应的 HTTP 请求。对于Web应用而言,发出的 HTTP 请求越多,加载所需的时间就越长,对于性能的影响就越大。如果你的页面中使用到多个字体时,就要面对 HTTP 请求增多的事实。实际上,我们可以按下面这种方式对请求做相应的优化,可以减少 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">

资源提示

资源提示(Resource Hints)是现代浏览器支持的一种特性,可以用来提高网站的性能。该特性包含了 prefetchpreloadpreconnectdns-prefetchprerender 等。它们可以用于 <link> 标签的 rel 中,告诉浏览器预加载一些东西:

<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相关的技术感兴趣的话,还可以阅读下面相关的教程进行扩展:

本地字体

谷歌字全是在”Libre“或”自由软件“许可下授权的,它允许你在没有请求许可的情况下自由使用、更改和分发字体。言外之意,如果你不想使用谷歌的主机,可以自己托管。甚至可以将字体下载到自己本地,做一些其他的优化。

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

font-display

font-display 属性提供了几个不同的属性值,对于字体的加载可以做相应的优化。 font-display 常常和 @font-face 配合在一起使用:

@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 属性对浏览器加载字体的相关影响:

Web技巧(12)

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

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

使用text参数

Google Fonts API还有一个特性,应该是提供了 text 参数。这个很少使用的参数允许你只加载所需要的字符。例如,如果你的文本Logo(使用文本制作的Logo)需要唯一的之际体,则可以使用 text 参数只加载制作Logo需要的字符:

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 属性而言,他可以适用于任何一个加载字体的地方。

其他字体加载的优化

很多同学可能会有困惑,自己在Web中开发时,使用到Google Fonts API的场景并不多,甚至是没有。那么要怎么来优化字体的加载呢?事实上还是有很多字体加载的优化方式值得我们去探究和深挖。

CSS字体加载API

很早之前, @Bram Stein提到使用 fontFaceObserver 来对字体加载做优化 。现在,我们可以不借助任何的Polyfill,在浏览器中使用原生的JavaScript API也可以做相关的优化,比如 FontFaceSet.load()

如果你担心浏览器是否支持该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早在2016年对于 @font-face 的使用时加载字体就探讨过有关于字体加载方面的策略 ,用文章中的一张图来描述:

Web技巧(12)

最近, @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);
}

字全加载优化其他资料

字体加载的不同策略直接会影响到网站的性能,用户的体验。如果你平时的项目中常常会用到 @font-face 来加载一些Web非安全字体,或者使用一些字体图标。那么就很有必要多了解字体加载、字体性能优化方面的相关知识和技巧。如果你感兴趣的话,建议花一些时间阅读下面这些文章:

CSS 字体新玩法之彩色字体

Web技巧(12)

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

选择字体配色:font-palette

彩色字体通过 CPAL 表是可以拥有多种不同的配色方案的。 font-palette 有三个内置的参数以及支持自定义配色来达到修改配色方案的效果。

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

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

@font-palette-values 用于定义指定字体的配色规则。它允许开发者不仅可以自由选择字体内置的各种配色方案,还能自定义配色方案。而 font-palette 选择自定义配色方案也是通过本规则设置。

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

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

字体变体font-variation-*

在CSS中可以通过 font-variant-* 属性来控制大多数 OpenType 特性。 font-variant-* 主要包括:

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

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

CSS中的镜像

前端时间@袁川 老师再次向大家展示了CSS的艺术。即 使用CSS制作中国式的窗棂 :

Web技巧(12)

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

Web技巧(12)

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

CSS Transform实现镜像

最简单的方式就是使用 CSS的 transform 中的 scaleX(-1) 实现水平镜像, scaleY(-1) 实现垂直方向的镜像效果。比如你有一张这样的图:

Web技巧(12)

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

Web技巧(12)

-webkit-box-reflect实现镜像

该特性是真正用来制作镜像的。其主要包括以下几个属性值:

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

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

Web技巧(12)

CSS element()函数

CSS Image Values and Replaced Content Module Level 4 中有一个 element() 函数。 这个函数可以将网站中的某部分当作图片渲染。当一个DOM元素在浏览器中得到正确的渲染时,其实得到的就是一张图片。而且元素修改之后,得到的图片也会立马改变。

Web技巧(12)

使用该函数配合 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 》(译文)中向大家 演示的案例

Web技巧(12)

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

小结

Web技巧系列 的第10期中,我们聊天了排版相关的技巧。而排版中或者说Web制作中都离不开字体的使用。在之一期中我们主要和大家一起探讨了Web中怎么使用 @font-face 来加载非安全的Web字体(也就是自定义字体,或系统中不具备的字体)。 @font-face 除了可以让我们使用带有艺术范或个性化的字体之外,还可以使用它来实现字体图标。不管家文本还是图标都会涉及到字体的制作与转换,因此简单的一起聊了一下怎么制作字体和转换字体。

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

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


以上所述就是小编给大家介绍的《Web技巧(12)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数字化生存

数字化生存

(美)Nicholas Negroponte(尼古拉·尼葛洛庞帝) / 胡泳、范海燕 / 电子工业出版社 / 2017-1-1 / 68.00

《数字化生存》描绘了数字科技为我们的生活、工作、教育和娱乐带来的各种冲击和其中值得深思的问题,是跨入数字化新世界的*指南。英文版曾高居《纽约时报》畅销书排行榜。 “信息的DNA”正在迅速取代原子而成为人类生活中的基本交换物。尼葛洛庞帝向我们展示出这一变化的巨大影响。电视机与计算机屏幕的差别变得只是大小不同而已。从前所说的“大众”传媒正演变成个人化的双向交流。信息不再被“推给”消费者,相反,人们或他......一起来看看 《数字化生存》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具