2

Web Font

上一篇讲的主要是本地字体的解决方案。有时候,本地字体并不能满足我们的使用需求,这种情况下,就要用到Web Font

@font-face

这是一个叫做@font-face 的CSS @规则 ,它允许网页开发者为其网页指定在线字体。 通过这种作者自备字体的方式,@font-face 可以消除对用户电脑字体的依赖。 @font-face 不仅可以放在在CSS的最顶层, 也可以放在 @规则 的 条件规则组 中。

@font-face {
  font-family: 'MyWebFont';
  src: url('webfont.eot'); /* IE9 Compat Modes */
  src: url('webfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
       url('webfont.woff2') format('woff2'), /* Super Modern Browsers */
       url('webfont.woff') format('woff'), /* Pretty Modern Browsers */
       url('webfont.ttf')  format('truetype'), /* Safari, Android, iOS */
       url('webfont.svg#svgFontName') format('svg'); /* Legacy iOS */
}
  

也可以使用本地路径

在另一个文档中使用本地字体或引用SVG字体:

 @font-face {
  font-family: Headline;
  src: local(Futura-Medium),
       url(fonts.svg#MyGeometricModern) format("svg");
}

在编辑器中引用字体:

  @font-face {
  font-family: 'myfont';
  src: url(fonts/NotoSansCJKsc-Regular.ttf);
}

像这样在样式元素中使用:

body{
    font-family:'MyWebFont',Fallback,sans-serif;
}

Font File Types

String Font Format Common extensions Description
"embedded-opentype" Embedded OpenType .eot EOT是嵌入式字体,是微软开发的技术。允许OpenType字体用@font-face嵌入到网页并下载至浏览器渲染,存储在临时安装文件夹下。
"truetype" TrueType .ttf Windows和Mac系统最常用的字体格式,其最大的特点就是它是由一种数学模式来进行定义的基于轮廓技术的字体,这使得它们比基于矢量的字体更容易处理,保证了屏幕与打印输出的一致性。同时,这类字体和矢量字体一样可以随意缩放、旋转而不必担心会出现锯齿。
"opentype" OpenType .ttf,.otf OpenType是微软和Adobe共同开发的字体,微软的IE浏览器全部采用这种字体。致力于替代TrueType字体。
"woff" WOFF(Web Open Font Format) .woff WOFF(Web开发字体格式)是一种专门为了Web而设计的字体格式标准,实际上是对于TrueType/OpenType等字体格式的封装,每个字体文件中含有字体以及针对字体的元数据(Metadata),字体文件被压缩,以便于网络传输。
"woff2" WOFF2(Web Open Font Format 2.0) .woff2 WOFF2是下一代WOFF,拥有比原来更好的压缩性。
"svg" SVG Font .svg, .svgz SVG是由W3C制定的开放标准的图形格式。SVG字体就是使用SVG技术来呈现字体,还有一种gzip压缩格式的SVG字体。

Browser Support

- Chrome Firefox Opera Safari IE / Edge
TTF/OTF 4 3.5 10 3.1 9[1]
WOFF 5 3.6 11.10 5.1 9
WOFF2 36 39 23 10 Not supported
SVG 4-37[2] Not supported 9-24[2] 3.2 Not supported
EOT Not supported Not supported Not supported Not supported 6
  1. 字体只能在设置为“可安装”时工作。

  2. SVG FONT 的问题在于文件体积很大,有时甚至超过原始的 TTF/OTF 字体文件。Chrome从38开始,Opera从25开始不支持SVG FONT,这种字体在Windows Vista和XP下依然能用。

如果只需要支持较新的浏览器,那么请使用:

@font-face {
  font-family: 'MyWebFont';
  src:  url('myfont.woff2') format('woff2'),
        url('myfont.woff') format('woff');
}
Chrome Safari Firefox Opera IE Android iOS
5+ 5.1+ 3.6+ 11.50+ 9+ 4.4+ 5.1+

需要对较旧的浏览器进行支持:

@font-face {
  font-family: 'MyWebFont';
  src: url('myfont.woff2') format('woff2'),
       url('myfont.woff') format('woff'),
       url('myfont.ttf') format('truetype');
}
Chrome Safari Firefox Opera IE Android iOS
3.5+ 3+ 3.5+ 10.1+ 9+ 2.2+ 4.3+

需要支持IE:

 @font-face {
      font-family: 'MyWebFont';
      src: url('webfont.eot'); /* IE9 Compat Modes */
      src: url('webfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
           url('webfont.woff2') format('woff2'), /* Super Modern Browsers */
           url('webfont.woff') format('woff'), /* Pretty Modern Browsers */
           url('webfont.ttf')  format('truetype'), /* Safari, Android, iOS */
           url('webfont.svg#svgFontName') format('svg'); /* Legacy iOS */
    } 

这就是所谓的Fontspring @font-face语法,它是最初的Bulletproof @font-face语法的最新版本。结合使用@font-face格式描述符和各种附加编码,这种语法开发用于诱导浏览器使用它们支持的最佳的(或者在某些情况下是唯一的)Web字体格式。不幸的是,事实证明最初的语法无法防弹(Bulletproof)。经过各种迭代,它必须不断更新来克服各种问题,比如对移动支持和最新浏览器版本(比如IE9)支持的限制。

获取字体

推荐几个常用的字体下载网站Google FontsAdobe Typekitdafont阿里妈妈webfont有字库

免费中文字体列表

字体转换可以使用transfonter或者fontsquirrel,这样你就可以在只有一个文件的情况下,将其转换成不同的文件格式。需要注意的是这两个网站只支持英文字体。

convertio支持中文转换,最大支持到100M,相当不错。

字体压缩,就要使用下面的解决方案:

Fontmin 是一个纯 JavaScript 实现的字体子集化方案。

提供了 ttf 子集化,eot/woff/svg 格式转换,css 生成 等功能,助推 webfont 发展,提升网页文字体验。

font-spider通过分析本地 CSS 与 HTML 文件获取 WebFont 中没有使用的字符,并将这些字符数据从字体中删除以实现压缩,同时生成跨浏览器使用的格式。

字体加载策略

在你引入的字体被渲染出来之前,他们需要先进行加载。下面是三种在加载的时候可能会发生的事情:

  1. 引入的字体没有被识别出来,字体应用了备用字体。

  2. 引入的字体虽然被识别出来但是没有加载,他需要在下载完成之后才会被应用。

  3. 引入的字体被成功识别并迅速应用。

场景1只发生在你尝试使用一个不存在的字体,或者声明时候的src指向了一个坏链,这种情况可以彻底避免。

场景2包含着字体加载过程,字体加载通常是难以避免的(至少是在第一次请求的时候),下面是处理方式:

字体加载示意图

@font-face

随意把@font-face代码块放置在你的网页中并且希望这是最好的办法. 这是 Google Fonts 推荐的默认方式.

font-display

在你的 @font-face 代码块中增加一个新的 font-display: swap 描述符选择性加入支持 FOUT 的浏览器。另外, 如果考虑到在线字体不是你设计一定需要的, 可以使用 font-display: fallback font-display: optional

到现在为止,只有ChromeOprea支持本属性。

Demo: font-display

预加载 preload

Preload是为处理当前页面所生,这点和 subresource 一样,但他们之间有着细微且意义重大的区别。Preload 有 as 属性,这让浏览器可做一些 subresource 和 prefetch 无法实现的事:

  • 浏览器可以设置正确的资源加载优先级,这种方式可以确保资源根据其重要性依次加载, 所以,Preload既不会影响重要资源的加载,又不会让次要资源影响自身的加载。

  • 浏览器可以确保请求是符合内容安全策略的,比如,如果我们的安全策略是Content-Security-Policy: script-src 'self',只允许浏览器执行自家服务器的脚本,as 值为 script 的外部服务器资源就不会被加载。

  • 浏览器能根据 as 的值发送适当的 Accept 头部信息

    • "script"

    • "style"

    • "image"

    • "media"

    • "document"

    • 更多请参考fetch spec

  • 浏览器通过 as 值能得知资源类型,因此当获取的资源相同时,浏览器能够判断前面获取的资源是否能重用。

web 字体是较晚才能被发现的关键资源(late-discovered critical resources)中常见的一类 。

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

需要注意的一点是:crossorigin 属性是必须的,即便是字体资源在自家服务器上,因为用户代理必须采用匿名模式来获取字体资源。

更快的获取到你的字体。配合 @font-face 代码块使用并且也可以和 font-display 描述符号一起锦上添花。

切记: 这个实现方式的利弊完全取决于配合使用的加载策略, 无论是 随意使用 @font-face 或者 font-display

Demo: preload

内嵌数据 URI

这个方法有两种嵌入式(的代码块): 一个是 <link rel="stylesheet"> 请求或在 <style> 在服务器渲染标记语言中。

alibaba.com (在 CSS 请求中有两个在线字体)

<link rel="stylesheet" href="//i.alicdn.com/sc-aisn/home2017/??common.d2b5f7f7.css"/>

medium.com (7个在线字体)

<link rel="stylesheet" type="text/css" href="https://cdn-static-1.medium.com/_/fp/css/fonts-hinted-base.nXqTvl3tOo9dXbn4BRwJAg.css" />

都使用了这个实现方式。

Demo: Inline Data URI

异步数据 URI 样式表

使用类似 loadCSS 的工具获取样式表, 所有的字体都嵌入在数据 URI 中。你也将竟然看到这个配合一个本地存储方法来把这个样式表存储在用户本地供其他视图重复使用。

Demo: Asynchronous Data URI Stylesheet

有分类的 FOUT

使用 CSS 字体库中的加载API函数(polyfill)去检测当有某一个字体被加载时, 只将这个成功加载的在线字体应用到你的 CSS 中。同时这意味着放置一个开关类在你的 <span><html></span> 元素上。使用 SASS/LESS 进行更简单的维护操作。

Demo: FOUT with a Class

结论: 这是标准线. 被大部分情况使用。

FOFT或两个渲染阶段的FOUT

该实现基于 有分类的 FOUT 方法, 当你要对同一个字型加载不同的字体粗细和样的时候是非常有用的, 比如, Roman , Bold , Italic , Bold Italic , Book, Heavy 等等。 我们可以将在线字体分为两个阶段: Roman 优先, 之后将立即渲染faux-boldfaux-italic的内容(使用字体合成), 然后真实的在线字体, 大权重和加载其他样式。

Demo: FOFT, or FOUT with Two Stage Render

严格的 FOFT

这个方法和标准的 FOFT 实现方式不同的是, 在第一阶段不是完全的 Roman 在线字体, 我们使用 Roman 在线字体的一个子集(通常只会包含 A - Z 和 0 - 9 或标点符号)。 完全的 Roman 在线字体在第二阶段加载不同的权重和样式。

Demo: Critical FOFT

有数据 URI 的严格 FOFT

这个不同的 FOFT 实现方式可以通过第一阶段加载的内容来改变机制。我们可以简单的以直接嵌入数据 URI 到标记语言的形式, 嵌入在线字体, 而不是使用一般的 JavaScript API 来初始化一个下载, 加载字体。就如之前讨论的, 这样会阻塞初始化渲染, 但是由于我们仅嵌入一小部分的子 Roman 在线字体, 对于完全消除FOUT, 这点代价还是值得的。

Demo: Critical FOFT with Data URI

结论: 就我来看, 这就是目前的黄金标准。

有预加载 preload 的 严格 FOFT

这个不同的 FOFT 实现方式可以通过第一阶段加载的内容来改变机制。我们使用新的 preload 在线标准, 而不是使用一般的 JavaScript API 来初始化一个下载, 加载字体。在之前已经介绍过 preload方法, 这会比之前更快的触发下载。

Demo: Critical FOFT with preload

结论: 当浏览器能更好的支持的时候,这会是新的黄金标准。

详细对比请看:字体加载策略全面指南

网络字体加载器:Font Face Observer以及Web Font Loader

unicode-range

unicode-range是CSS一个属性,一般跟@font-face搭配使用。

unicode-range: U+4??;              /* 通配符区间 */

这里面的问号可以理解成占位符,表示0~FU+4??表示U+400U+4FF

中文汉字和常见英文数字等的unicode编码范围实例页面

那么它的主要作用是什么呢?它的用处主要是可以指定特定的字符使用特定的字体。

&字符使用Palatino字体

双引号修改为宋体

漢字標準格式 这里面的标点就用到了unicode-range,看_biaodian.scss

排版

相对大小

尽可能的使用相对大小。

html { font-size: 100% }
p { font-size: 1em }

@media (min-width: 64em) {
  html {
    font-size: 112.5%;
  }
}
  • font-size: 100% 与浏览器的字体大小设定保持一致而不是去覆写它,根据大多数的浏览器的默认设置,这里也可以用1em 代替表示 16px.

  • 通过改变htmlfont-size会影响到所有单位为 emrem 的元素.如果是对于响应式设计的网页,这样做还是比较实用的。

  • 用户的选择也很重要,所有不要偏离 font-size: 100%1em太远.

  • 对于font-size建议使用remem.

  • 对于一些元素定位如margin, padding等等,建议使用 rem, em, 或者%

  • 对于媒体查询中尺寸建议使用em.

  • 对于一些大的标题字或者配有图片的字,可以使用FitText来实现标题的缩放。尽量避免使用vwvh 因为现在的支持还不是很好,难于精确的配置,并且对于一些浏览器的字体和缩放设置并不适配 。

容器

容器,或者成为包装,指的是用来包裹一个或者多个元素的HTML元素。它将元素分组,从而更好进行语义化、修饰以及布局。

html {
  box-sizing: border-box;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

.container {
  max-width: 67rem;
  padding-left: 1.5rem;
  padding-right: 1.5rem;
}
  • 强烈建议使用 box-sizing: border-box. 点击这里 查看更多信息。

  • 左/右内间距与最大宽度联合使用可以很容易地创建一个移动端友好的容器。

  • 要为容器选择一个合适的宽度,既不能太大(因为太大的话读者的眼睛难以聚焦)也不能太小(这样读者的眼睛需要经常移动才可以看清)。永远记住,在进行网页字体排版的时候,没有一个适合所有字体、尺寸、行距和分辨率的铁律,你需要自己来做决定。

字体大小

使用 缩放模块 可以帮助你决定在你的元素上面应用怎样的font-size .缩放模块指的是依照其内容安排的一系列比较合适的字体大小的数值。

缩放模块的说明. 点击此处

  • 我们可以在编写CSS的一开始使用缩放模块,将它作为一个参考。

  • 值的注意的是,尽管不同的字体有着不同的大写字母高度和x字母高度,可是大多数的模块化缩放工具都没有将这些考虑在内。

  • 在你的样式表中,建议将你所使用到的缩放模块工具的配置信息写在注释之中。

响应式的缩放模块

只使用单独的一个缩放模块方案并不一定适合所有分辨率的设备,为了解决这个问题,你可以依据用户的设备的分辨率的不同提供不同的缩放方案

//Sass responsive modular scale

/* 
 * Modular scale
 * http://www.modularscale.com/?1.25&em&1.33&web&text
*/

$type-scale-large: (
  h1: 3.911rem,
  h2: 2.941rem,
  h3: 2.211rem,
  h4: 1.663rem,
  p: 1.25rem
);

/* 
 * Modular scale
 * http://www.modularscale.com/?1.25&em&1.25&web&text
*/

$type-scale-medium: (
  h1: 3.052rem,
  h2: 2.441rem,
  h3: 1.953em,
  h4: 1.563rem,
  p: 1.25rem,
);

/* 
 * Modular scale
 * http://www.modularscale.com/?1.1&em&1.25&web&text
*/

$type-scale-small: (
  h1: 2.686rem,
  h2: 2.148rem,
  h3: 1.719rem,
  h4: 1.375rem,
  p: 1.1rem
);

$breakpoint-medium: 75em;
$breakpoint-small: 45em;

@mixin size($level) {
  font-size: map-get($type-scale-large, $level);
  @media (max-width: $breakpoint-medium) {
     font-size: map-get($type-scale-medium, $level);
  }
  @media (max-width: $breakpoint-small) {
     font-size: map-get($type-scale-small, $level);
  }
}

// Example

.title {
  @include size(h1);
}

垂直距离

文字间的垂直距离是由 line-height, margin, 和padding构建出来的.

  • line-height 不应该带有单位。比较宽的容器里面文字的行高会大一些,而那些比较窄的容器里面行高相对来说小一些会比较合适。

  • 为那些具有单方向的文本元素添加margin属性,建议使用margin-bottom

  • 要遵循距离原则

垂直节律

垂直节律是指元素之间的垂直间隔要保持一致性。这一点十分重要,它可以带给读者视觉上放松的享受,给他们一种亲近的感觉。

Image source

建立垂直节律很简单。首先,确定你使用的基础垂直内间距和基础垂直外间距的数值。然后,为你的容器,文字性元素或者其他相关元素的单方向的外边距(或者内边距)应用这个数值。如果你需要制制造更大的间隔的话,应用这个数值的倍数就好啦!

将基础间距的数值设置成与行高相同的数值,这样你的文字就像写在一个条格纸上那样整齐,就像我们传统的印刷字体设计的那样。然而,想要文字拥有垂直节律不一定需要按照上面的方法来做,只要你设置了一个基础间距,并且使得其他间距都是由这个间距成倍的得来的,那样就可以了。

body { 
  line-height: 1.4; // Base line height
}

p { 
  font-size: 1.25em; // Base font size
  margin-bottom: 1.75rem; // Base vertical spacing: (1.4 * 1.25) = 1.75
}

h1 {
  font-size: 3em;
  margin-bottom: 3.5rem; // Double the base value for a larger gap (1.75 * 2) = 3.5
}

h2 {
  font-size: 2em;
  margin-bottom: 1.75rem;
}

h3 {
  font-size: 1.5em;
  margin-bottom: 1.75rem;
}

.page-container {
  padding: 3.5rem 2rem; // 3.5 is double the base value
}

/* Simple Sass Implementation */

$base-line-height: 1.4;
$base-font-size: 1.25rem;
$vertical-rhythm: $base-line-height * $base-font-size;

body { 
  line-height: $base-line-height;
}

p { 
  font-size: $base-font-size;
  margin-bottom: $vertical-rhythm;
}

h1 {
  font-size: 3em;
  margin-bottom: $vertical-rhythm * 2;
}

h2 {
  font-size: 2em;
  margin-bottom: $vertical-rhythm;
}

h3 {
  font-size: 1.5em;
  margin-bottom: $vertical-rhythm;
}

.page-container {
  padding: ($vertical-rhythm * 2) 2rem;
}

Note that rem is used for spacing as it is not influenced by the font-size of the element.

文字底部对齐基线网格

文字底部对齐基线是垂直节律的一个更为严格的实现。在网页中,文字通常在line-height间居中对齐.但对于较大的文字来说会比较讨厌,因为这样做会导致在顶部和底部留有太多的空间。在传统印刷的时候,这个问题一般会通过让文字对齐基线网格的底部得以解决。

我们也可以通过为较大的文字添加一个负的margin-top和一个较小的margin-bottom,不需要使用基线网格而解决这个问题。

图片资源

为不同的字体样式、字体大小和分辨率添加一个底部对齐的基线网格并不是一个很容易的方式,所以强烈建议你使用一个字体排版基线库例如 Sassline 或者 MegaType.

注意,垂直节律只是一个建议,而且基线网格也只是想象出来的。所以我们不需要在每个使用场合都遵循这个规律,也不用在每个元素中都去追求像素级别的完美。

颜色

颜色可以很大程度上的增加视觉辨识度,是字体排版中一个重要的组成部分。

不要随心所欲的挑选颜色,建议使用颜色板,建议你使用 Material Design colorsFlat UI colors 中提供的颜色板进行颜色选择.
不要过度滥用一个颜色,因为这样会造成辨识度的降低,同样也不要使用很多完全不同的颜色。
遵循相似原则.
不建议使用纯黑 #000 作为你的正文颜色,你可以选择一个非常灰的颜色如#333.
有时候,使用透明颜色比使用浅色会更好一些,如果你深入的了解,可以点击这里
确保文字和背景有较大的对比度,你可以使用 这个对比度检测工具 帮助你进行选择.

下划线

在印刷品里,永远都不要使用到下划线,因为这样做会影响文字的阅读,重点是,它很丑!Practical Typography

一般的来说,在网页中下划线也会看起来并不美好!幸运的是, background-image 就包含一个方法,它可以使得下划线变得好看一点。 下面是Adam Schwartz使用Sass实现的下划线的例子 :

@mixin text-underline-crop($background) {
  text-shadow:  .03em 0 $background, 
                  -.03em 0 $background,
                  0 .03em $background,
                  0 -.03em $background,
                  .06em 0 $background,
                  -.06em 0 $background,
                  .09em 0 $background,
                  -.09em 0 $background,
                  .12em 0 $background,
                  -.12em 0 $background,
                  .15em 0 $background,
                  -.15em 0 $background;
}

@mixin text-background($color-bg, $color-text) {
  background-image: linear-gradient($color-text, $color-text);
  background-size: 1px 1px;
  background-repeat: repeat-x;
  background-position:  0% 95%;
}

@mixin text-selection($selection) {
  &::selection {
    @include text-underline-crop($selection);
    background: $selection;
  }

  &::-moz-selection {
  @include text-underline-crop($selection);
  background: $selection;
  }
}

@mixin link-underline($background, $text, $selection){
  @include text-underline-crop($background);
  @include text-background($background, $text);
  @include text-selection($selection);

  color: $text;
  text-decoration: none;

  *,
  *:after,
  &:after,
  *:before,
  &:before {
    text-shadow: none;
  }

  &:visited {
    color: $text;
  }
}

/* Example usage */
a {
  @include link-underline(#fff, #333, #0CBF);
}

clipboard.png

SmartUnderline 是一个简化这个工作的库。
建议你只在有链接的地方使用下划线,这是大多是网站都遵循的规律,如果不这么做的话,可能会引起误解。

Using @font-face

Web版式和@font-face简介 - InfoQ

Preload: What Is It Good For?

Preload: What Is It Good For?中文翻译版

字体排版手册

CSS unicode-range特定字符使用font-face自定义字体

妙用UNICODE-RANGE实现字体混搭


人丑就要多读书_
197 声望17 粉丝