Css权威指南(4th,第四版中文翻译)-5.字体

关于字体,最早在1996年的CSS1规范中就开始了,设置字体属性一直是CSS的核心功能之一。
到了CSS2,支持了通过@font-face来自定义字体。虽然规范出的早,不过也是到了2009年才大面积普及开来,而且也有不少像Typekit的网站来支持网络字体的使用。

虽说下载自己的字体不错,不过万一断网了,字体下载失败了,或是浏览器解析错误直接导致乱码就凉凉了,所以一般浏览器都有plan B,当下载失败的话就用默认自带的来代替。

Font Families

说到字体,其实一般指的是一个集合,因为同一种字体也需要对粗体,斜体等做单独的设定。就拿最常见的Times字体为例,就包括了TimesRegular, TimesBold, TimesItalic, TimesBoldItalic等多个变体,而每个变体都是font face。

为了覆盖比较广的使用范围,CSS定义了5中通用的字体家族:

  1. Serif fonts(衬线字体):该字体的主要特征为2个,一个是比例字体(相对于等宽字体来说,像i和m就具有不同的宽度)。衬线字体的代表比如Times,Georgia和New Century Schoolbook。

  2. Sans-serif font:该字体的特点是比例字体,但是没有衬线。典型的有Helvetica, Geneva, Verdana, Arial 和 Univers.

  3. Monospace font(等宽字体):顾名思义最大特点就是等宽,字母i和m具有相同的宽度。典型的有Courier, Courier New, Consolas 和 Andale Mono.

  4. Cursive font(草书字体):这类字体主要是模拟人类书写的样式。典型的有Zapf Chancery, Author 和 Comic Sans。

  5. Fantasy fonts:有时也被称为装饰字体或是显示字体,一般来说特征不是特别明显,例如Western, Woodblock 和 Klingon.

一般来说这5大类已经包含了绝大多数的font family,其余少数的可以统一归到fantasy font。

使用通用的font-families

css中font-family的语法是:

如果文档里需要使用sans-serif字体,但又不确定用哪个,可以这些设置:

body {font-family: sans-serif;}

虽然使用单一的字体类型在页面上比较合适,不过同时使用多个也是可以的:

body {font-family: serif;}
h1, h2, h3, h4 {font-family: sans-serif;} 
code, pre, tt, kbd {font-family: monospace;} 
p.signature {font-family: cursive;}
5-1.png

指定字体类型

指定具体的类型也是通过font-family来操作:

h1 {font-family: Georgia;}
5-2.png

如果浏览器没有找到Georgia字体,那就会启用默认字体。如果想要进一步,那么在设置完具体字体后可以设置通用的font-family,比如像下面这样:

h1 {font-family: Georgia, serif;}
h1 {font-family: Arial, sans-serif;}
h2 {font-family: Charcoal, sans-serif;}
p {font-family: 'Times New Roman', serif;} address {font-family: Chicago, sans-serif;}

如果想要设置浏览器选择的顺序,那么就可以用逗号分割一系列的字体:

p {font-family: Times, 'Times New Roman', 'New Century Schoolbook', Georgia, 'New York', serif;}

使用引用标记

你可能已经注意到了上面例子中的单引号,就是因为中间有空格,所以通过单引号来保持内容的完整,除了空格,像#和$也是可以的,举个例子:

h2 {font-family: Wedgie, 'Karrank%', Klingon, fantasy;}

虽然在现代浏览器中不需要加引号,不过还是推荐加上。不过要注意的是别再通用字体上加引号,因为这会让浏览器以为是某个具体的字体。
单引号和双引号都是可以的,如果要在style属性中设定的话:

<p style="font-family: 'New Century Schoolbook', Times, serif;">...</p>

使用 @font-face

说实话,这个属性早在CSS2的时候就提出过了,不过知道最近才实现,让用户可以指定字体。

@font-face {
font-family: "SwitzeraADF";
src: url("SwitzeraADF-Regular.otf");
}

描述符

所有的对字体的设置都可以在@font-face{}里完成,其中有两个是必须的:font-family和src


t5-2.png

src属性支持多个来源的定义,中间以逗号分隔。虽然可以引用多个位置,但是路由上是受同源策略限制的,如果想要引用其他网站上的字体,最好download一份到自己的服务器上。

有人可能好奇为什么这边又来了个font-family的定义,其实这里的@font-face就相当于一个全局注册功能,将想要的字体添加到浏览器的默认字体列表中,这样在需要引用字体的样式中就可以直接调用了:

@font-face {
font-family: "SwitzeraADF"; /* descriptor */ src: url("SwitzeraADF-Regular.otf");
}

h1 {font-family: SwitzeraADF, Helvetica, sans-serif;} /* property */

font-face中的font-family更像是一种变量的声明,而h1中的font-family属性则是对这一变量的引用。

5-4.png

对于多个src的字体,浏览器就挨个处理,如果上一个下载失败,就会自动处理下一个,依次递推:

@font-face {
font-family: "SwitzeraADF";
src: url("SwitzeraADF-Regular.otf"),
url("/fonts/SwitzeraADF-Regular.otf");
}

如果想让浏览器知道你下载的字体是哪种类型的,可以借助format字段,定义的话参考下面:

@font-face {
font-family: "SwitzeraADF";
src: url("SwitzeraADF-Regular.otf") format("opentype");
}

那浏览器知道了格式又有什么好处呢?是这样的,如果没有format字段,一般的流程是,直接下载下来,然后解析判断下文件类型是否支持,不支持的话再下载下一个。如果提前先定义好类型,浏览器就会先看下自己是否支持该类型文件的解析,如果不支持那就直接跳过下载,直接看下一个url,因此用的好的话可以节省带宽。另外一个好处是,如果下载文件的后缀不是常规的字体类型,但其实文件内容又属于某个常用的类型,那就需要让浏览器明白这一陌生后缀对应的类型:

@font-face {
font-family: "SwitzeraADF";
src: url("SwitzeraADF-Regular.otf") format("opentype"),
}

我们在下表中累出了浏览器能识别的文件类型:

format属性值 对应的文件类型
embeded-opentype EOT(Embedded OpenType)
opentype OTF(OpenType)
svg SVG(Scalable Vector Graphics)
truetype TTF(TrueType)
woff WOFF(web Open Font Format)

在src的语法中,除了url和format意外,还可以设定font-family的别名,以防止同名字体的产生,使用的关键字是local,来看下示例:

@font-face {
font-family: "SwitzeraADF"; 
src: local("Switzera-Regular"),
       local("SwitzeraADF-Regular "), 
       url("SwitzeraADF-Regular.otf") format("opentype"),     
       url("SwitzeraADF-Regular.true") format("truetype");
}

而且local不止可以对新的字体重命名,对已有的也可以:

@font-face {
font-family: "H";
src: local("Helvetica"), local("Helvetica Neue");
}
h1, h2, h3 {font-family: H, sans-serif;}

浏览器兼容性

比较坑的一点是,不同浏览器,不同版本对不同字体的支持是不一样的,所以为了最大程度兼容,我们的最佳实践是提供一系列不同类型的字体,这就是所谓的"Bulletproof @font-face语法",最早是Paul Irish发明的,后来被FontSpring的人修改过,看起来就像这样:

@font-face {
font-family: "SwitzeraADF";
src: url("SwitzeraADF-Regular.eot");
src: url("SwitzeraADF-Regular.eot?#iefix") format("embedded-opentype"),
}
url("SwitzeraADF-Regular.woff") format("woff"), 
url("SwitzeraADF-Regular.ttf") format("truetype"), url("SwitzeraADF-Regular.svg#switzera_adf_regular") format("svg");

咱们来仔细分析下,首先是这两句:

src: url("SwitzeraADF-Regular.eot");
src: url("SwitzeraADF-Regular.eot?#iefix") format("embedded-opentype"),

EOT格式主要是针对IE6-IE9的,第一行是IE9的兼容模式,而第二行是针对IE6-IE8的。最重要的就是这个'?#iefix',这个表达式其实是利用了一个解析上的bug,其最终的效果就是对IE6-IE8的浏览器,让它们直接跳过后面的字体路径解析,返回一个404。
接下来是:

  url("SwitzeraADF-Regular.woff") format("woff"),

这一行应用了woff字体,这是现代浏览器的主流的字体格式,覆盖绝大多数的PC端用户。

url("SwitzeraADF-Regular.ttf") format("truetype"),

ttf格式能够覆盖大多数的IOS和Android设备,覆盖大多数手持设备用户。

url("SwitzeraADF-Regular.svg#switzera_adf_regular") format("svg");

最后的svg格式主要针对一些老的IOS设备,基本能够覆盖剩余的手持设备用户。

看起来要写一系列的兼容字体还是很繁琐的,所以有很多现成的font-face生成器来直接生成一系列的字体格式。

其他的字体描述符

除了上面提到的font-family和src描述符,还有不少可选的属性来设置字体的特性,统一在下表中列出:

描述符 默认值 说明
font-style normal 包括normal,italic和oblique
font-weight normal 表示字体的weight,例如bold
font-stretch normal 定义不同角度的字母宽度
font-variant normal 字体变体类型,类似font-feature-settings
font-feature-settings normal 允许低级的OpenType特点,例如启用连字
unicode-range U+0-10FFFF 设置给定字体所能允许的unicode范围

由于这些字体描述符都是可选的,所以没有全部列在@font-face里面。如果用户没有设置的话,那就用默认的代替。

限制字体范围

unicode-range在CSS属性中没有对应的特性,这个选项可以限制font face在某个用户想要的范围里面。默认情况下,该属性覆盖所有的Unicode字符集,而在其他情况下,就需要用户指定不停字体对应的字符集范围。来看个例子:

unicode-range: U+590-5FF; /* Hebrew characters */
unicode-range: U+4E00-9FFF, U+FF00-FF9F, U+30??; /* Japanese kanji,
        hiragana, katakana */

在第一行中,我们将范围限定在590到5FF的Unicode字符集中,覆盖了希伯来语(Hebrew)。在第二行中,我们用逗号分隔制定了多个范围来覆盖所有的日语字符集。最有意思的是最后的U+30??,这个表示什么含义呢?其实这是在unicode-range中特有的语法,问号代表任意字母的通配符(类似于正则表达式),所以上面的U+30??其实就等于U+3000-30FF。问号是其中仅有的特殊符号。

注意范围的顺序必须是从小到大,任何从大到小的范围都会解析为非法而被忽略掉。除了范围单个的字符编码也是允许的:

unicode-range: U+4E00-9FFF, U+FF00-FF9F, U+30??, U+A5;
/* Japanese kanji, hiragana, and katakana, plus yen/yuan currency symbol*/

另外由于@font-face现在已经被优化了,通过懒加载来实现,所以可以借助unicode-range来下载特定的字体。举例来说,如果你做了个网站支持英文、俄语和基本的算术符号,但是你不清楚某个页面到底显示哪些符号,可能都是英语,也可能混杂着俄语和数学符号。同时我们假定你已经有了包含这三种语言的字体,那怎么来设置font-face呢?

@font-face {
font-family: "MyFont";
src: url("myfont-general.otf" format("opentype");
} 
@font-face {
font-family: "MyFont";
src: url("myfont-cyrillic.otf" format("opentype");
unicode-range: U+04??, U+0500-052F, U+2DE0-2DFF, U+A640-A69F, U+1D2B-1D78;
} 
@font-face {
font-family: "MyFont";
src: url("myfont-math.otf" format("opentype"); unicode-range: U+22??; /* equivalent to U+2200-22FF */
}

我们来分析下,第一个定义没有限定范围,所有一定会被全部下载,第二个规则定义了当包含特定字符范围的字体,而第三个规则用户算数字体。

描述符的结合使用

为了达到针对某个具体的属性要求,我们可以将多个描述符结合起来来实现。比如说对粗体文字设置一种字体,而对斜体文字又指定一种字体,再对粗斜体再指定一种。让我们来看下如何实现:

@font-face {
font-family: "SwitzeraADF";
font-weight: normal;
font-style: normal;
font-stretch: normal;
src: url("SwitzeraADF-Regular.otf") format("opentype");
}

@font-face {
font-family: "SwitzeraADF"; font-weight: bold; font-style: normal; font-stretch: normal;
src: url("SwitzeraADF-Bold.otf") format("opentype"); }

@font-face {
font-family: "SwitzeraADF";
font-weight: normal;
font-style: italic;
font-stretch: normal;
src: url("SwitzeraADF-Italic.otf") format("opentype");
}
5-5.png

Font Weights

font-weight 翻译为字体权重不太合适,因为它主要描述的是字体的粗细,除了上面已经看到的常见的normal和bold意外,其实还有很多特性:

t5-3.png

一般来说,你weight设置的越大,字体就越黑越粗。当设置粗体字体时:

b {font-weight: bold;}

浏览器会自动选择粗体对应的font face,例如对于Times字体来说,那么就是TimesBold。

weights的原理

浏览器是如何处理字体的weight的呢,其实其默认会分成9级,从100到900,就是之前表中列出的9个,100最轻,而900最重。而每一等级都没有固有的粗细重量,比如说很有可能,100,200,300,400都对应同一粗细的字体,500,600对应一种,而700,800,900再对应一种。只要前者比后者细就行。一般来说,400对应normal,700对应bold,其他的依次类推。
如果给定的font-family中少于9级,那就要依赖浏览器自行判断,下面是几条判断的规则:

  • 如果500没有指定,那就跟400的一样;
  • 如果300没有指定,那就取比400小的字体,如果没有小的了,就拿400的代替;
  • 如果600没有指定,默认取比500大的字体,如果没有大的了,就取500的,对700,800,900也是一样的。

变粗些

如果你把font-weight的值设置为bolder,那么浏览器就会先判断下从父类继承下来的粗细是啥样,然后在此基础上选取更粗的字体来设置。

p {font-weight: normal;}
p em {font-weight: bolder;} /* results in bold text, evaluates to '700' */

h1 {font-weight: bold;}
h1 b {font-weight: bolder;} /* if no bolder face exists, evaluates to '800' */

div {font-weight: 100;} /* assume 'Light' face exists; see explanation */ div strong {font-weight: bolder;} /* results in normal text, weight '400' */
5-7.png

更轻些

跟bolder类似,lighter会搜寻比当前weight更轻的字体,就不再赘述了。

font-weight描述符

这里说的描述符指的是在font-face定义的font-weight,用来标记下载的字体对应的weight层级。

@font-face {
font-family: "SwitzeraADF";
font-weight: normal;
src: url("f/SwitzeraADF-Regular.otf") format("opentype");
} 
@font-face {
font-family: "SwitzeraADF";
font-weight: bold;
src: url("f/SwitzeraADF-Bold.otf") format("opentype");
} 
@font-face {
font-family: "SwitzeraADF";
font-weight: 300;
src: url("f/SwitzeraADF-Light.otf") format("opentype");
} 
@font-face {
font-family: "SwitzeraADF";
font-weight: 500;
src: url("f/SwitzeraADF-DemiBold.otf") format("opentype");
} 
@font-face {
font-family: "SwitzeraADF";
font-weight: 700;
src: url("f/SwitzeraADF-Bold.otf") format("opentype");
} 
@font-face {
font-family: "SwitzeraADF";
font-weight: 900;
src: url("f/SwitzeraADF-ExtraBold.otf") format("opentype");
}

由于上面讲各类粗细的字体都设置过了,因此我们就可以看到不同层级的字体大小:

h1, h2, h3, h4 {font: 225% SwitzeraADF, Helvetica, sans-serif;} h1 {font-weight: 900;}
h2 {font-size: 180%; font-weight: 700;}
h3 {font-size: 150%; font-weight: 500;}
h4 {font-size: 125%; font-weight: 300;}
5-11.png

Font Size

说完了字体weight,下面来看下更常用的字体大小:


t5-4.png

跟font-weight类似的,font-size也有smaller和larger来选取更大一号和更小一号的字体尺寸。
让我们深入字体大小的本质,其实际的尺寸是由字体的设计者决定的。这里有个概念称之为em square(有些人又叫做em box),em 盒子跟字符的边框没啥关系,但跟baseline的距离有关(在不设置line-height的情况下)。又因为对因为字母来说,很多字母是很容易超出baseline之间的,碰到这种情况就要求所有超出的字母必须设计在baseline里面,来看几个例子:

5-12.png

所以从上面可知,我们设定大小是怎么作用到字体的呢,是通过设置em box的盒子大小实现的,潜台词是不能保证所有显示出来的字符都是同一个大小。

绝对大小

在font-size中有7个绝对大小的值:xx-small, x-small, small, medium,large,x-large和xx-large。指的注意的是,这些值并不是准确定义的,而其实是相对定义的,什么意思呢?就是每一个值都是按比例放大和缩小的,按照CSS1的规范,每层级以1.5倍的大小递增,或者反过来说,以0.66左右的倍数在尺寸递减。所以说如果medium是10px的话,那么large就是15px。不过在CSS2中,觉得这个倍数太大了,所以建议缩小为1到1.2之间,而到了CSS3,在草稿中定义的更加复杂,是按分数来定义的,比如说small为medium的8/9,而xx-small为medium的3/5。所以其核心就是这个比例因子,不过不同浏览器有权按照自己的想法来指定。

5-13.png

相对大小

比较来说,larger和smaller还是挺简单的,参照父元素的字体大小,然后按一定的比例来增大或是减小。不过和font-weight不同的是,size其实是没有大小的绝对限制,因为是按比例缩放的:

h1 {font-size: xx-large;} 
em {font-size: larger;}
<h1>A Heading with <em>Emphasis</em> added</h1>
<p>This paragraph has some <em>emphasis</em> as well.</p>
5-14.png

百分比大小

百分比也是另一种相对大小的单位,参照的也是从父元素继承下来的大小,相比于之前的比例缩放,百分比提供了更细腻的大小控制。来看个示例:

body {font-size: 15px;}
p {font-size: 12px;}
em {font-size: 120%;}
strong {font-size: 135%;} small, .fnote {font-size: 70%;}
<body>
<p>This paragraph contains both <em>emphasis</em> and <strong>strong emphasis</strong>, both of which are larger than their parent element.
The <small>small text</small>, on the other hand, is smaller by a quarter.</p> <p class="fnote">This is a 'footnote' and is smaller than regular text.</p>
<p> 12px <em> 14.4px </em> 12px <strong> 16.2px </strong> 12px <small> 9px </small> 12px </p>
<p class="fnote"> 10.5px </p>
</body>
5-15.png

知道么,CSS中的em单位其实背后就是用百分比来调节的,1em其实就是100%的字体大小,所以下面两个是一致的:

p.one {font-size: 166%;} 
p.two {font-size: 1.6em;}

字体大小的继承

来看个继承的例子:

p {font-size: 12px;}
em {font-size: 120%;} 
strong {font-size: 135%;}
<p>This paragraph contains both<em>emphasis and <strong>strong emphasis</strong></em>, both of which are larger than the paragraph text. </p>
<p>12px <em>14.4px <strong> 19.44px </strong></em> 12px</p>
5-16.png

em的大小是多少呢?12px X 120% = 14.4px,而strong的大小为14.4 px × 135% = 19.44 px,所以说百分比的大小是累积的。

显示的四舍五入

在所有现代浏览器中,font-size的数值的显示精度都是内部自动维护的,渲染引擎也不会使用到这个。来看个例子:下图中列出了大部分浏览器显示的字母o的序列,而从左往右每个都在左边的基础上加了0.1px,最左边的o默认都是10px,最中间的是10.5px,而最右边是11px:


5-17.png

虽然实际显示的时候有差异,不过在数值上都是一样的,例如每个右起的第3位的大小都是10.8px。

等宽文本的关键词

p {font-size: medium;} /* the default value */ 
span {font-family: monospace; font-size: 1em;}
<p>This is a 'p' with a <span>'span'</span> inside.</p>
5-18.png

注意上面的span元素设置的font-family为等宽字体,那这个宽度是多少呢?如果外部的p为16px的话,是不是这里也是16px呢?答案是不一定,有可能是,如果浏览器的默认medium是16px的话,但如果用户在偏好设置中将等宽字体设置为13px的话,那么不管你外层是16px,还是说你强制设置为font-size:1em,都没用。浏览器将按照预设的13px来渲染等宽字体。

上面提到浏览器对这一操作的反馈其实是有差异的,那么有没有一种通用的设置方法保证一致性的,答案当然是有的:

p {font-size: medium;} /* the default value */ 
span {font-family: monospace, serif; font-size: 1em;}
<p>This is a 'p' with a <span>'span'</span> inside.</p>

与之前的唯一差别就是serif字段的添加,导致的效果就是让浏览器完全采用父元素的字体大小作为100%来设置,所以1em就等于父元素大小。

使用长度单位

font-size属性其实可以使用任意的长度单位,下面的几个长度都是一样的:

p.one {font-size: 36pt;} 
p.two {font-size: 3pc;} 
p.three {font-size: 0.5in;} 
p.four {font-size: 1.27cm;} 
p.five {font-size: 12.7mm;}
5-20.png

另外跟上面值一样的还有36px,不过有个前提条件,就是屏幕的分辨率为72px每英寸(ppi)。然而,随着显示器的发展,老早就超过了这个水平,现在普遍的pc浏览器的分辨率在96ppi到120ppi,而对于手机来说则更高,达到300ppi到500ppi。

虽然有各类的单位,不过大家普遍使用的还是像素的单位,尤其是在包含有文字和栅格图(GIF,JPG,PNG等)的网页中,因为font-size可以同时设置图片和文字的大小。

虽然看起来使用像素来设置font-size可以得到一致的显示效果,但实际上还是有缺陷的。主要问题发生在移动端,有些浏览器会不支持像素定义的文本大小,结果会导致样式的混乱,比如说iphone默认就是全屏的显示,所以如果想要覆盖全部浏览器,全都用像素来定义大小可能不合适。

自动调整大小

对于字体的显示效果有两个指标,自己的大小和x的高度,因此定义了(x高度)/font-size的比值称为aspect value,字体的比值越高,那么在缩放时效果保留的更好,反之就有可能出现显示差异。而在CSS中为了能够调整不同font-family的比值,退出了font-size-adjust:


t5-5.png

还是举例来说吧,Verdana和Times两个字体本身就差距明显,来看下处理前的效果:

p {font-size: 10px;}
p.cl1 {font-family: Verdana, sans-serif;} 
p.cl2 {font-family: Times, serif; }
5-22.png

从图上可以看出来,Times明显比Verdana文字更粗,或者说更硬些,部分原因就是因为像素的定义引起的。Verdana的比例为0.58,因此来试下:

p {font: 10px Verdana, sans-serif; font-size-adjust: 0.58;} 
p.cl2 {font-family: Times, serif; }
5-23.png

这样看起来效果就差不多了。不过这个比例从哪获取呢,一般来说font-face的导入的字体中会有相关的信息,如果没有的话浏览器也会自己去算,所以可以使用auto字段,来达到相同的效果:

p {font: 10px Verdana, sans-serif; font-size-adjust: auto;} 
p.cl2 {font-family: Times, serif; }

当然啦,如果把font-size-adjust设置为none,就会把调整给关掉。

Font Style字体样式

font-style相对简单,选项就3个:normal, italic,oblique。稍微难点的就是italic和oblique的区别,虽然看上去都是斜体。

t5-6.png

font-style默认值为normal,基本本书的大多数情况都是normal的,形象的说法就是笔直的,而不直的为什么有两个呢,来看下两者的区别:


5-24.png

从上面可以看出来,这两个对基于字母连成单词的语言效果明显,就英语来说,italic在每个字母的倾斜上其实是做了处理的,可以看看勾的地方,像serif,Italic,Cursive,Kursiv等很明显都是italic的,而oblique则是完整保留整体的情况下做了倾斜处理,默认的有Oblique, Slanted和Incline。做个形象的中文比喻,italic更像是草书,而oblique更像是华文正楷的倾斜版。

很多字体其实italic和oblique都是一样的,没有精细的差别。至于斜体有什么用呢,举个例子,在一段引用中字体一般是斜体的,但是其中重点突出的文本又想要笔直的,我们可以这样设置:

blockquote {font-style: italic;}
blockquote em, blockquote i {font-style: normal;}
5-27.png

font-style 描述符

在font-face中可以通过指定font-style来选择具体的样式版本:

@font-face {
font-family: "SwitzeraADF";
ont-style: normal;
src: url("SwitzeraADF-Regular.otf") format("opentype");
} 
@font-face {
font-family: "SwitzeraADF";
font-style: italic;
src: url("SwitzeraADF-Italic.otf") format("opentype");
} 
@font-face {
font-family: "SwitzeraADF";
font-style: oblique;
src: url("SwitzeraADF-Italic.otf") format("opentype");
}
h1, h2, h3 {font: 225% SwitzeraADF, Helvetica, sans-serif;} 
h2 {font-size: 180%; font-style: italic;}
h3 {font-size: 150%; font-style: oblique;}
5-28.png

Font Stretching

在有些font family中,还会涉及到字体的宽窄变化,例如Condensed,Wide, Ultra Expanded等。在CSS中可以通过font-stretch实现,而不用在font-family中详细定义。

t5-7.png

font-stretch的使用有个特点,就是加宽和缩短需要字体文件的支撑,否则就不会有变化,不像font-size可以任意设置变化。来看个例子:

body {font-family: Verdana;}
strong {font-stretch: extra-expanded;} 
footer {font-stretch: extra-condensed;}
5-29.png

font-stretch描述符

就跟font-weight类似,在font-face里面也可以定义font-stretch描述符。看个例子:


@font-face {
font-family: "SwitzeraADF";
font-stretch: normal;
src: url("SwitzeraADF-Regular.otf") format("opentype");
} 
@font-face {
font-family: "SwitzeraADF";
font-stretch: condensed;
src: url("SwitzeraADF-Cond.otf") format("opentype");
} 
@font-face {
font-family: "SwitzeraADF";
font-stretch: expanded;
src: url("SwitzeraADF-Ext.otf") format("opentype");
}
h1, h2, h3 {font: 225% SwitzeraADF, Helvetica, sans-serif;} 
h2 {font-size: 180%; font-stretch: condensed;}
h3 {font-size: 150%; font-stretch: expanded;}
5-30.png

Font Kerning字体字距

在有些字母组成的语言,比如英文中,字母间的空隙间隔也是不同的,例如oc和ox这种字母组合其实间隔就是有区别的,还比如AB和AW在显示上面也是不同的,这些字体间距的差别可以通过font-kerning来设置。

t5-8.png

上面3个选项非常简单,none表示不适用字距,normal表示按照字体里面定义的来,而auto则将字距完全交给了浏览器,让其判断如果添加字距。

Font Variants

除了上述几个属性,还包括不同的字体变化,这是通过font-variant来设置的:


t5-9.png

有没有发现CSS3的时候多了很多,原先CSS1.0, CSS2.0默认的就是normal和small-caps小写,这里还是重点关注下这两个值吧。来看个例子:

h1 {font-variant: small-caps;}
h1 code, p {font-variant: normal;}
<h1>The Uses of <code>font-variant</code> On the Web</h1> <p>
The property <code>font-variant</code> is very interesting... </p>
5-31.png

设置完后,发现原本相同的大写内容也出现了不同的大小变化。这是与text-transform:uppercase;不同的地方,虽然其他地方都类似。那么这个font-variant如果做small-caps,其实很大程度上依赖字体本身是否支持,否则的话还是移交给浏览器自行判断。

CSS3的值

上图中css3的值列了一大串,实际上归结起来就是一下这几种:

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

举例来说,<common-lig-values>就是来自font-variant-ligatures,值的话就是common-ligatures和no- common-ligatures,<numeric-fraction-values>来自font-variant-numeric, 对应的值有diagonal-fractions or stacked-fractions。其他的以此类推。

在使用变体的过程中主要有两个障碍:浏览器支持和字体支持。第一个简单,到2017年底为止,CSS2.1的变体基本都支持了,但是3.0的只有Gecko和WebKit的浏览器支持。而后面一个字体支持就复杂了,不同字体间的可支持变体区别很大,所以最好还是按照字体的文档来设置。

font-variant描述符

功能其实不用多说,直接上例子:

font-variant: common-ligatures small-caps slashed-zero;

Font Synthesis

字体合成顾名思义就是让浏览器在特定情况下自己生成对应的字体,比如说bold或是italistic。

t5-10.png

为了防止浏览器自动生成的字体比较丑,你可以设置font-synthesis: none。

5-32.png

字体属性

字体的属性还是不少的,如果要挨个写还比较麻烦:

h1 {font-family: Verdana, Helvetica, Arial, sans-serif; font-size: 30px; font-weight: 900; font-style: italic; font-variant: small-caps;}
h2 {font-family: Verdana, Helvetica, Arial, sans-serif; font-size: 24px;
font-weight: bold; font-style: italic; font-variant: normal;}

所以为了简化书写,我们可以来定义font属性:


t5-11.png

所以上面的一系列定义可以简化成:

h1 {font: italic 900 small-caps 30px Verdana, Helvetica, Arial, sans-serif;} 
h2 {font: bold normal italic 24px Verdana, Helvetica, Arial, sans-serif;}
5-33.png

细心的读者可能注意到了,上面对属性的顺序是没有要求的,比如第一个的顺序是font-style,font-weight,font-variant,而第二个的顺序为font-weight,font-variant,font-style。顺序可以任意调换,下面的写法跟上面也是一样的:

h1 {font: italic 900 small-caps 30px Verdana, Helvetica, Arial, sans-serif;} 
h2 {font: bold italic 24px Verdana, Helvetica, Arial, sans-serif;}

上面我们看到随意的部分,下面来看看必须遵守的要求,就是font属性的最后两个属性,必须是font-size和font-family,而且顺序是固定的:

h1 {font: normal normal italic 30px sans-serif;} /*no problem here */
h2 {font: 1.5em sans-serif;} /* also fine; omitted values set to 'normal' */ h3 {font: sans-serif;} /* INVALID--no 'font-size' provided */
h4 {font: lighter 14px;} /* INVALID--no 'font-family' provided */
5-34.png

添加行高

是不是很奇怪,行高line-height其实是text的属性,怎么会出现在font里面,其实这属于是约定的设置,通过一个斜杠来实现/:

body {font-size: 12px;}
h2 {font: bold italic 200%/1.2 Verdana, Helvetica, Arial, sans-serif;}
5-35.png

如果要设置行高的话,必须前面有font-size,比如上面例子中,font-size实际值为24px,而行高为1.2*24px=28.8px。

正确的使用简写

如果乱写font的话有时候会导致意想不到的结果,比如下面这个例子:

h1, h2, h3 {font: italic small-caps 250% sans-serif;} 
h2 {font: 200% sans-serif;}
h3 {font-size: 150%;}
<h1>This is an h1 element</h1> 
<h2>This is an h2 element</h2> 
<h3>This is an h3 element</h3>
5-36.png

有没有发现h2元素默认设置为normal了,没有bold或是italic,因为font设置的时候如果没有设定,默认会将所有属性设定为默认的normal,所以上面跟下面是一样的:


h1, h2, h3 {font: italic normal small-caps 250% sans-serif;} 
h2 {font: normal normal normal 200% sans-serif;}
h3 {font-size: 150%;}

使用系统字体

有时候在开发页面的时候想要使用用户操作系统的字体,下面是系统字体的一些属性:

  • caption: 用户caption控制,例如buttons
  • icon:使用标签icon
  • menu:在菜单里使用
  • message-box:在dialog box中使用
  • small-caption:用于标记小写控制
  • status-bar: 用于窗口状态栏

举个例子,如果要将按钮的字体设置为系统的,可以这样:

button {font: caption;}

一般来说,你设置完系统字体后,那么像样式,weight等属性都会默认使用系统的,除非你要单独设置的:

button {font: caption; font-size: 1em;}

当然了,如果浏览器没有找到对应的字体,那么它就会自动找替代方案,评估和你预期的最接近的。

字体匹配

之前我们看到,CSS会去自动匹配font family, weight和variant,那么这个匹配的规则是什么样的呢?

  1. 浏览器首先维护者一个关于字体的数据库,当定义不同字体属性的时候都会进行相关的查询和设置;
  2. 字体首先匹配font-stretch属性
  3. 接下来匹配font-style属性
  4. font-weight
  5. font-size

小结

从最简单的字体属性开始,CSS到现在已经发展了一套功能齐全的属性来满足定制化要求。同时也支持定义外部的字体,这极大扩展了字体的范围和功能。但这也对作者或是网页开发者提出了更高的要求,需要权衡包括性能等多个角度。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • 我知道我的累来自于哪里,大概就是自身对于自己整日无所事事,找不到在这个世界上存在的价值的无力感,其实身体比思想更加...
    凹凸曼奥阅读 190评论 0 0
  • 拿到了兔子的书,猪通宵达旦地读了起来,忘了吃饭,忘了睡觉。 第二天,猪非常兴奋地过来找兔子。 ...
    林子奇阅读 757评论 3 8
  • 在10月19日结束的东京世锦赛半决赛中,中国女排经历了五局的鏖战,最终惜败于世界强队意大利,遗憾未能进入最后决赛。...
    夜吟光寒阅读 907评论 1 4