这一期中咱们将围绕着Web中的font
来展开。在现代Web中除了能使用font-family
属性给Web应用指定字体以外,还有其余一些用于字体的特性,好比@font-face
能够加载非系统的字体,字体变体属性font-variation-*
让Web上排版和印刷上排版之间的差距在逐渐拉小,font-display
属性来决定非系统方面字体的加载策略,提升性性能,font-palette
用来选择字体配色,@font-palette-values
自定义字体配色等。若是你感兴趣的话,请继续往下阅读。javascript
现代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 Icon@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中的中文字体,并非咱们系统常见的字体,好比“宋体”、“楷体”、”萍方“和”微软雅黑“等。拿个示例来讲吧,在UI还原中,你确定碰到带有艺术字体的设计稿:
碰到这样的场景大部分解决方案,要么是使用系统默认字体,要么是使用图片来替换。或许你会问:
既然
@font-face
这么牛逼,为何中文艺术字体不用该特性呢?
缘由很是简单,对于英文而言,它只有26
字母,一张ASCII码上128
个字符集,体量较小,设计成本较小。但对于中文而言,单单GB2313
编码的中文字字符就达到7445
个,体量较大,设计成本较大。这就是中文相比于英文不太好设计的缘由之一,若是要设计出这么一套中文字体(带艺术性,个性化字体),除了设计成本和难度较大以外,就算是设计出来,字体体积也很是的大,面对这么大的字体文件,要是运用于Web上,也不是件易事。最起码要面对字体的加载,性能的优化等问题。
不过并非没有任何方案可解,在社区中也有相应的字体裁剪工具,好比:
就算是有了这些工具,咱们也没法大面积的在Web上使用特殊的中文字体。而在中文Web应用程序中,使用这种艺术字体的场景也不是全站都是,大部分会出如今标题、Banner等场景。而这样的场景下所需的字体数量有限的,这样咱们就能够借助上面的两个工具对字体进行裁剪,生成一个只包含特定字符的小字体文件。这样就达到了减小字体文件的目标。
有关于这方面的详细介绍能够阅读下面几篇文章:
@font-face
前面提到过,使用@font-face
使用第三方字体的时候受限于字体的大小,网络的影响等,对用户的体验是会有相应的影响。除了下降字体包的大小以外还有一些别的优化方式。好比@Danny Cooper在他的最新博客中就聊到了如何优化Google Fonts性能。在这篇文章中提到的一些优化方案其实都适合使用@font-face
的任何地方。
下面简单的来了解一下@Danny Cooper在文章中给咱们介绍哪些技术手段能对字体方面作相关的优化。
无论是使用的Google Fonts仍是其余地方提供的字体。能够说每种字体在Web浏览器中显示以前都须要先下载。经过正确的设置,额外的加载时间并不明显。可是,若是出现错误,用户可能须要等待必定的时候才能显示。接下来,做者拿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
种变体,就过于浪费,由于你可能只会用到3
或4
种变体。例如,Roboto
字体系列的重量大约为144kb
。可是,若是你只使用常规的,常规的斜体和粗体等,那么这个字体的重量就能够降低到大约36kb
,至关于节约了75%
。
通常状况下,加载Google Fonts的默认代码以下:
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
复制代码
这样作,只是加载了常规400
(Regular 400
)版本。这意味着字体集中的其余版本,好比Light
、Bold
和Italic
将不会正确的显示。若是要改变这个现象,即 要加载全部字体变体,能够在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">
复制代码
前面也提到过了,不多网站会使用全部字体的变体,从100
到900
,而实际使用中,最佳的方式是指定你可能须要的字体变体权重,好比:
<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">
复制代码
无论是使用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)是现代浏览器支持的一种特性,能够用来提升网站的性能。该特性包含了prefetch
、preload
、preconnect
、dns-prefetch
和prerender
等。它们能够用于<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-prefetch
和preconnect
对于字体加载方面的优化有很大的做用。
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
的请求完成以后,浏览器才会开始处理这些请求。
也能够说preconnect
是prefetch
的加强版。它是在浏览器将要加载的特定URL
上设置它。它不只执行DNS
查找,还完成了TSL
协商和TCP
握手。
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
复制代码
仅仅添加这一行代码就能够将页面加载时间减小100ms
。
若是你对Resource Hints相关的技术感兴趣的话,还能够阅读下面相关的教程进行扩展:
谷歌字全是在”Libre“或”自由软件“许可下受权的,它容许你在没有请求许可的状况下自由使用、更改和分发字体。言外之意,若是你不想使用谷歌的主机,能够本身托管。甚至能够将字体下载到本身本地,作一些其余的优化。
另外,谷歌字体还提供一个服务,容许你选择要使用的字体,而后提供所需的文件和CSS。
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" >
复制代码
在href
的URL
地址上配合font-display
一块儿使用&display=swap
。
font-display
它还能实现相似于Font Loading API和Bram Stein's Font Face Observer这种第三方脚本实现的功能。
用一张简单的图来描述font-display
属性对浏览器加载字体的相关影响:
特别声明,上图来自于@monica的《Font-display》一文。
有关于font-display
属性更多的相关介绍能够阅读:
font-display
的用法font-display
font-display
: The Future of Font Rendering on the WebGoogle 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的场景并很少,甚至是没有。那么要怎么来优化字体的加载呢?事实上仍是有不少字体加载的优化方式值得咱们去探究和深挖。
很早以前,@Bram Stein提到使用fontFaceObserver
来对字体加载作优化。如今,咱们能够不借助任何的Polyfill,在浏览器中使用原生的JavaScript API也能够作相关的优化,好比FontFaceSet.load()
。
若是你担忧浏览器是否支持该API,能够先对其作相应的判断:
;(function () {
if (!('fonts' in document)) return;
})();
复制代码
若是不支持,那程序会直接return
掉,释放程序。该方法使用promise
在加载字体后运行函数。该函数将会传递font-size
和name
做为参数,并使用.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
}
})();
复制代码
若是你对这方面的知识感兴趣的话,还能够阅读下面相关文章:
FontFaceSet.load()
methodFontFaceSet.load()
method instead of the CSS font-display: swap
property?@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 Fonts Module Level 4工做草案中提供了一些新特性,即为Color Font提供了相应的描述。
彩色字体经过 CPAL 表是能够拥有多种不一样的配色方案的。font-palette
有三个内置的参数以及支持自定义配色来达到修改配色方案的效果。
normal
:浏览器尽量地将该字体看成非彩色字体进行渲染,并选择一个最适合阅读的配色方案。浏览器在作决策时还可能将当前设定的字体颜色color
加入决策条件中。还有可能自动生成一组未内置在字体中的配色方案进行渲染。light
:一些彩色字体在其元数据中标明某个配色方案适用于亮色(接近于白色)背景中。使用此数值,浏览器将会直接使用标记了该特性的首个配色方案进行渲染。若是字体文件格式无元数据或时元数据中未标记相应的配色方案,那么此时该数值的行为与 normal
相同dark
:正好与light
相反@font-palette-values
的帮助。@font-palette-values
用于定义指定字体的配色规则。它容许开发者不只能够自由选择字体内置的各类配色方案,还能自定义配色方案。而font-palette
选择自定义配色方案也是经过本规则设置。
它的基本定义规则是@font-palette-values name
,name
即为本配色规则的自定义规则名称。
若是你对彩色字体感兴趣的话,能够阅读早前整理的一文章。
在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的-webkit-box-reflect
属性。印象中最先接触该属性的时候大约是在2014年的时候,就尝试着使用了这个属性来实现一些倒影或镜像的效果。
而在CSS中实现镜像效果的技术方案不只局限于-webkit-box-reflect
属性。接下来,简单的聊聊CSS中的镜像。
最简单的方式就是使用CSS的transform
中的scaleX(-1)
实现水平镜像,scaleY(-1)
实现垂直方向的镜像效果。好比你有一张这样的图:
使用上面提到的方法,能够很容易的实现水平和垂直方向的镜像效果:
该特性是真正用来制做镜像的。其主要包括如下几个属性值:
none
:此值为-webkit-box-reflect
默认值,表示无倒影效果;<direction>
:此值表示-webkit-box-reflect
生成倒影的方向,主要包括如下几个值:above
生成的倒影在对象(原图)的上方;below
生成的倒影在对象(原图)的下方;left
生成的倒影在对象(原图)的左侧;right
生成的倒影在对象(原图)的右侧;<offset>
:用来设置生成倒影与对象(原图)之间的间距,其取值能够是固定的像素值,也能够是百分比值,如:使用长度值来设置生成的倒影与原图之间的间距,只要是CSS中的长度单位均可以,此值可使用负值;使用百分比来设置生成的倒影与原图之间的间距,此值也可使用负值<mask-box-image>
:用来设置倒影的遮罩效果,能够是背景图片,也能够是渐变生成的背景图像。好比@袁川 老师在教程中向你们演示的案例,就是使用该特性制做的一个中国式窗棂效果:
在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-reflect
和element()
等来实现镜像效果。最后,但愿这一期中讨论的东西,你们会喜欢。若是您在这方面有相关的经验,或有较好的建议,欢迎在下面的评论中与咱们一块儿讨论。