Web技巧(12)

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

@font-face的使用

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

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

@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只须要调用相关的资源连接,需使用的时候指定相应的图标类名便可:java

上面看到的字体都是现成的,若是你是一名设计师或者说你懂得字体的设计。那么你就能够在任何Web页面或Web应用上使用你本身设计的字体。这样一来,是否是很是有成就感。一样的原理,还能够设计一些SVG矢量图标,借助IcoMoon Web App将图标生成Web可用的Web字体:css3

若是你对Web中字体图标相关的东西感兴趣的话,还能够阅读下面相关文章:git

@font-face带来不少优点,但大多人通常只会聊自定义的Web字体如何定义,可是没有过多的人考虑其实际性能:github

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

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

如何使用第三方字体

你或许常常会看到有网站像下面这样的引用非系统的字体:

<!-- 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中的中文字体

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

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

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

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

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

就算是有了这些工具,咱们也没法大面积的在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

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

特别声明,上图来自于@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的使用时加载字体就探讨过有关于字体加载方面的策略,用文章中的一张图来描述:

最近,@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 字体新玩法之彩色字体

若是说,使用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制做中国式的窗棂:

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

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

CSS Transform实现镜像

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

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

-webkit-box-reflect实现镜像

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

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

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

CSS element()函数

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

使用该函数配合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中实现镜像相的技术感兴趣的话,还能够阅读下面相关教程:

小结

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

既然使用@font-face特性,都将面临字体的加载,无论是线上(从CDN加载字体)仍是加载本地字体,都要考虑怎么作字体加载。因此这一期中,大部分篇幅和你们一块儿聊聊怎么来优化字体加载,提升页面性能,从而改善用户体验。

最后再向你们展现了CSS另外一方面的能力,即,怎么使用CSS的transform-webkit-box-reflectelement()等来实现镜像效果。最后,但愿这一期中讨论的东西,你们会喜欢。若是您在这方面有相关的经验,或有较好的建议,欢迎在下面的评论中与咱们一块儿讨论。

相关文章
相关标签/搜索