9、CSS权威指南--第 5 章(p155)字体
5.1 字体族
CSS 定义了五种通用字体族:
衬线字体:这种字体中的字形宽度各异,而且有衬线。
无衬线字体: 这种字体中的字形宽度各异。
等宽字体:等宽字体中的字形宽度一样。一般用于显示编程代码或表格数据,这种字体的各个字符在横向上所占的空间是一样的。
草书字体:这种字体尝试模仿人类笔记或手写体。
奇幻字体:这种字体没有什么同意特征,一般无法将其归化到其它类别中的,便会将其放到“奇幻”篮子里。
5.1.1 使用通用字体族
字体族使用 font-family 属性声明。
5.1.2 指定字体族
建议始终在 font-family 规则中指定通用字体族,这样做相当于提供一种后备机制,在用户代理找不到匹配的字体时,选择一个字体替代。
如:h1 { font-family: Arial, Helvetica, sans-serif; }
当字体名称中有空格或符号的时候,建议对字体名称使用引号,如:html {font-family: Arial, 'karrank%';}
5.2 使用 font-face
font-face 的作用是让你在设计中使用自定义的字体。假设你想使用 字体没有广泛的安装,而是十分特别的字体,借助 @font-face 的魔力,
你可以定义一个专门的字体族名称,对应于服务器上的一个字体文件。用户代理将下载那个文件,使用它渲染页面中的文本,就好像用户的设备中安装了那个字体一样。
例子:
@font-face {
font-family: “SwitzeraADF”’;
src: url("SwizeraADF-Regular.otf");
}
用户代理见到 font-family: SwitzeraADF 声明后,会加载对应的 .otf 文件,然后使用它渲染文本。
@font-face 是惰性加载字型的,这表明,仅当需要使用指定的字型渲染文本时,才会加载,否则不加载。其实,浏览器不管是否需要,都会先行下载声明的全部字型,这是浏览器的缺陷。
5.2.1 必须的描述符
定义字体的全部参数都在 @font-face { } 结构中编写,这些参数称为描述符,与属性十分相似,格式为 descriptior: value;。
描述符有两个是必须的:font-family 和 src 。
这里的 fon-family 做描述符使用,而不是 CSS 的声明, src 的作用是,为定义的字型提供一个或多个源。如果是多个源,之间用逗号隔开。
字型的来源可以指向任何URI,不过有个限制:字型必须与样式同源。因此,src不能指向别人的网站,下载别人的字体。你要在自己的服务器中存储一分本地副本,或者使用同时提供样式表和字体文件的字体托管服务。
不过同源限制有个例外,那就是使用HTTP首部 Access-Control-Origin 设定服务器允许跨站加载。
URI(统一资源标识符)是一个指向资源的字符串。最通常用在 URL 上来指定 Web 上资源文件的具体位置。
(什么是URI - 我歌且谣 - 博客园 (cnblogs.com)) (完整URL - 我歌且谣 - 博客园 (cnblogs.com))
通过描述符 font-family:"MyFont"; 定义一个字体族名称之后,用户代理的字体族名称表中便会出现“MyFont”条目,与其他已有的字体族拥有同等地位,可以在font-family 属性的值中引用。
@font-face{
font-family: "MyFontFamily";
src: url(...);
}
p { font-family: "MyFontFamily"; }
如果想告诉用户代理所用的字体是什么格式,可以使用可选的format():
@font-face{
font-family: "MyFontFamily";
src: url("MyFontFamily.otf") format("opentype");
url("MyFontFamily.true") format("truetype");
}
除了使用url() 和 format() 组合之外,还可以使用 local() 指定已经安装在用户设备中的字体族名称(可以是多个):
@font-face{
font-family: "MyFontFamily";
src: local("MyFontFamily");
url("MyFontFamily.otf") format("opentype");
url("MyFontFamily.true") format("truetype");
}
这里,用户代理先检查设备中是否有名为“MyFontFamily"的字体族,如果有使用之,如果没有,尝试从远端下载url()中指定的字体文件。
注意,借助这个功能可以为本地安装的字体自定义名称。以MyFontFamily为例,可以在描述符 font-family中,将其值设置为 “MF”,这样“MF”就指代“MyFontFamily”,就可以在元素样式中使用。
如: h1 {font-family: MF;}
5.2.2 其他字体描述符
除了必须的font-family和src描述符,还有几个可选的描述符用于为字型指定属性值。
font-style :默认值normal ,区分常规、斜体和倾斜字型。
font-weight :默认值normal ,区分不同个字重(例如加粗)。
font-stretch : 默认值normal , 区分不同的字符宽度(例如紧缩和加宽)。
font-variant : 默认值normal ,区分众多字型变体(例如小号大写字母),在很多方面与CSS中的 font-feature-setting 很像。
font-feature-settings :默认值normal ,直接访问OpenType的底层特性(例如启用连字)。
unicode-range :默认值U+0-10FFFF,定义指定字体中可用的字符范围。
这些字体描述符是可选的,不必一定在@font-face规则中列出。CSS规定,描述符不像属性那样可以有默认值。如果没有某个可选的描述符,它的值将被设为默认值。因此,如果没有列出font-weight,其默认值为 normal 。
5.2.3 组合描述符
我们可以把多个描述符组合在一起为字型设定不同的属性。
<style> @font-face { font-family: "SwitzeraADF"; font-weight: bold; font-style: italic; src: url("SwitzeraADF-Regular.otf") format("oepntype"); } </style>
5.3 字重
一般来说,字重越大,字体越黑,越粗。
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> <style>
/*
可用值 值的说明
normal 缺省值。字体正常显示。
bold 粗体
bolder 比粗体更加粗 !!!!!
lighter 比正常字体淡
100 至少和200一样淡
200 至少和100一样粗,至少和300一样淡
300 至少和200一样粗,至少和400一样淡
400 字体正常显示,相当于normal。!!!!!
500 至少和400一样粗,至少和600一样淡
600 至少和500一样粗,至少和700一样淡
700 粗体,相当于bold。!!!!!!
800 至少和700一样粗,至少和800一样淡
900 至少和800一样粗
*/
p:nth-child(1) {font-weight: bold;} p:nth-child(2) {font-weight: bolder;} p:nth-child(3) {font-weight: lighter;} p:nth-child(4) {font-weight: 100;} p:nth-child(5) {font-weight: 200;} p:nth-child(6) {font-weight: 300;} p:nth-child(7) {font-weight: 500;} p:nth-child(8) {font-weight: 700;} p:nth-child(9) {font-weight: 900;} </style> </head> <body> <p>font-weight: bold;</p> <p>font-weight: bolder;</p> <p>font-weight: lighter;</p> <p>font-weight: 100;</p> <p>font-weight: 200;</p> <p>font-weight: 300;</p> <p>font-weight: 500;</p> <p>font-weight: 700;</p> <p>font-weight: 900;</p> </body> </html>
b {font-weight: bold;} 这个声明的意思是,b元素应该使用粗体字型显示,即比常规字型粗一些的字型。其实在背后,显示b元素时会使用一个较粗的字型。
因此,如果一个段落使用Times显示,其中有部分加粗文本,那么这个段落其实是使用同一个字体的两个字型显示的:Times 和 TimesBold 。
常规文本使用 Times 显示,加粗文本使用 TimesBold 显示。
5.3.1 字重的工作方式
为了弄清用户代理如何确定一个字体变体的粗细(或字重),先要理解关键字 100 到 900 。这些数字关键字对应于字体设计中的九级字重。如果一个字体族中有全部九级字重,那个么这些数字就直接对应于与预定义的级别,100是最细的,900是最粗的。
其实,这些数字并不表示字重本身,CSS规范只是说,每个数字对应的权重至少和前面的数字具有相同的字重。
一般,100-900这些数字对应于常见的变体名称,400对应于 normal,700对应于bold ,其他数字不与 font-weight 的其他关键字对应。
如果给定的字体族中字重的等级少于9个,用户代理要做更多工作。遇到这种情况,用户代理必须填补既定方式的空缺:
(下面是CSS权威指南的介绍)
- 如果500未分配,与400对应的字重一样。
- 如果300未分配,将其对应于比400细的那个变体。如果没有这样一个变体,字重与400一样。200和100也是这样处理。
- 如果600未分配,将其对应于比500黑的下一个变体。如果没有这样一个变体,字重与500一样。700、800、900也是这样处理的。
书上没有介绍400没有分配会怎样。
(下面是MDN的介绍)
如果指定的权重值不可用,则使用以下规则来确定实际呈现的权重:
- 如果指定的权重值在
400
和500
之间(包括400
和500
):如果指定值小于400
,按降序查找小于指定值的可用权重。如果未找到匹配项,按升序查找大于指定值的可用权重(先尽可能的小,再尽可能的大)。- 按升序查找指定值与
500
之间的可用权重; - 如果未找到匹配项,按降序查找小于指定值的可用权重;
- 如果未找到匹配项,按升序查找大于
500
的可用权重。
- 按升序查找指定值与
- 如果指定值大于
500
,按升序查找大于指定值的可用权重。如果未找到匹配项,按降序查找小于指定值的可用权重(先尽可能的大,再尽可能的小)。
以上策略意味着,如果一个字体只有 normal
和 bold
两种粗细值选择,指定粗细值为 100-500
时,实际渲染时将使用 normal
,指定粗细值为 501-900
时,实际渲染时将使用 bold
。
5.3.2 增大字重 和 5.3.3 减少字重
如果把一个元素的字重设为border , 用户代理首先确定从父元素继承的 font-weight 值是什么,然后选择比继承的字重高一级的最数字。如果找不到,用户代理把元素的字重设为下一个数字值,直到900,到顶后,就把字重设为900。
lighter 的工作方式是让用户代理向下减小字重。
相对粗细值的解析:
当指定的是相对粗细值 lighter
或 bolder
时,将使用如下图表来决定元素渲染时的绝对粗细值:
继承值(Inherited value) | bolder | lighter |
---|---|---|
100 | 400 | 100 |
200 | 400 | 100 |
300 | 400 | 100 |
400 | 700 | 100 |
500 | 700 | 100 |
600 | 900 | 400 |
700 | 900 | 400 |
800 | 900 | 700 |
900 | 900 | 700 |
5.3.4 font-weight 描述符
类似于font-weight属性 的bolder 和lighter ,font-size 属性也有相对大小关键字,分别为 larger 和 smaller 。这两个关键字的作用与相对字重类似,分别增大和减小一号字体大小。
font-size属性与渲染结果之间的关系由字体设计者决定。这个关系在字体中通过em方框(或em盒子)表示。em方框(以及字号)与字体中字符的边界没有关系,其实它指的是在没有行距的(CSS中的 line-height)的情况下两条基线之间的距离。
字体中完全有可能存在高度超过基线之间距离的字符。鉴于此,设计字体时要确保所有字符都比em方框小。
因此,font-size的作用是为字体的em提供一个尺寸(一个尺寸单位?)。
5.4.1 绝对大小
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> <style> /*
font-size支持的绝对大小值有7个。 这几个关键字没有固定大小,而是相对而言的。根据CSS1规范,这些绝对大小之间相差的倍数(或叫换算系数)是向上1.5、向下0.66. 因此,如果medium相当于10px,那么large应该是15px。后来,人们觉得换算系数太大,在CSS3 的时候,提供了更为复杂的计算方式。 不过这些只是建议的换算系数,用户代理随时可以调整。 */ p:nth-child(1){font-size: xx-small;} p:nth-child(2){font-size: x-small;} p:nth-child(3){font-size: small;} p:nth-child(4){font-size: medium;} p:nth-child(5){font-size: large;} p:nth-child(6){font-size: x-large;} p:nth-child(7){font-size: xx-large;} </style> </head> <body> <p>xx-small</p> <p>x-small</p> <p>small</p> <p>medium</p> <p>large</p> <p>x-large</p> <p>xx-large</p> </body> </html>
5.4.2 相对大小
关键字 larger 和 smaller 根据父元素的字号增大或减小一定比例。这里使用的换算系数与计算绝对大小时一样。也就是说,如果浏览器计算绝对大小时使用的换算系数是1.2,计算相对大小关键字时用的也是1.2 。
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> <style> body { font-size: 26px; border: 1px solid red; } span:first-child{font-size: larger;} span:last-child{font-size: smaller;} span{border: inherit;} </style> </head> <body> <span>相较于父元素字号变大:larger</span><!-- --><span>继承父元素字号大小</span><!-- --><span>相较于父元素字号变小:smaller</span> </body> </html>
与字重的相对值不同,字号的相对值没有上下限。因此,字号可以小于xx-small 或大于xx-large 。
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> <style> p{ font-size: xx-large; border: 1px solid red; } p :first-child{ font-size: xx-large; color: red; } span{font-size: larger; border: inherit;}/* 第二个span字号要大于第一个span的xx-large, 因为使用了larger */ </style> </head> <body> <p><span>xx-large</span><span>larger</span></p> </body> </html>
5.4.3 百分数和 em
百分数在某种意义上与相对大小关键字很像。百分数始终根据继承自父元素的字号计算,与前面讨论的关键字相比,百分数能更细致的控制字号。
CSS还把长度单位em 定义为等效于百分数,对字号而言,1em 与 100% 的效果相同。(前提是同一个父元素)
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> <style> div{ display: inline-block; border: 1px solid red; } div:first-child{font-size: 160%;} div:last-child{font-size: 1.6em;} </style> </head> <body> <div>百分之一百六</div><!-- --><div>1em 等效于 100% ,用em表示就是1.6em</div> </body> </html>
5.4.4 字号的继承
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> <style> div{font-size: 10px;} p{font-size: 120%;} /* 相当于p{font-size: cale(10px * 120%);} 结果为12px */ em{font-size: 120%;} /* 相当于em{font-size: cale(12px * 120%);} 结果为14.4px 舍入为14px */ strong{font-size: 120%;} /* 相当于strong{font-size: cale(14px * 120%);} */ </style> </head> <body> <div> <p>CSS中的字号会继承 ! <em>但继承的是计算得到的值,而不是百分数本身 ! <strong>因此,strong 元素继承的值是14px,乘以声明的120% 后得到的计算值</strong> </em> </p> </div> </body> </html>
显示时舍入: 多数现代浏览器在内部维护着小数字号,但渲染引擎不一定会使用。尽管如此,如果使用审查工具,或者直接通过DOM 脚本查询, 你会发现,每个浏览器都会保留字号中的子像素。
关键字和等宽文本:字号继承和关键字继承会导致实际大小缩水,这在某些浏览器渲染等宽文本时尤为明显。
你可能以为span元素中的文本宽度也是16px , 这在某些浏览器中确实会如此,然而在有些浏览器中是 13px 。 原因在于,虽然段落中的文本经计算16px, 但是通过继承向下传递的是关键字 medium 。
因此span中的字号是根据medium计算的。 为了算出具体的字号,用户代理会查看用户的偏好设置,而多数浏览器为等宽文本设定的默认字号是 13px。
所以,即使明确为等宽文本设定 font-size: 1em; 在使用16像素字号的段落中,等宽文本依然显示13像素。
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> <style> p{font-size: medium;} span{font-family: monospace ; font-size: 1em;} </style> </head> <body> <p>(等宽文本)字号设为1em (或 100%) 之外的值时, <span>这个问题依旧存在。</span> </p> </body> </html>
然而,有个方法能绕开这个问题,而且对已知的浏览器都有效(至少是截止至2017年末)。具体方法如下:
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> <style> p{font-size: medium;} span{font-family: monospace, serif; font-size: 1em;} /* font-family 中多了个 serif ,这样做,在所有浏览器中, font-size: 1em 的意思都是段落实际字号的100% 。 而不再根据 medium 对应的值计算。这种方法适用于所有浏览器。 所以,心之忧矣,我歌且谣的文字大小是一致的。 */ </style> </head> <body> <p>心之忧矣 <span>我歌且谣</span> </p> </body> </html>
5.4.5 使用长度单位
font-size 可以设为任何长度值。使用像素值设定font-size 却是能保持字号已知(其实使用任何长度单位单位都是如此),但是有一个缺点:不是所有浏览器都能轻易缩放像素设定的文本(有时甚至不能缩放),
而且有时候使用像素值设定的文本在模仿全屏幕设备的移动设备中的实际字号特别小(例如多款iPhone)。
5.4.6 自动调整字号
有两个因素影响字体是否清晰易辨:字号和 x 高度。x 高度除以字号得到的结果称之为高宽比值。随着字号的减小,高宽比值越高,字体越清晰易辨;相反,高宽比值较低的字体,很容易变得模糊难辨。
CSS提供的 font-size-adjust 属性用于改变字体族之间的 高宽比值,它适用于所有元素,可以取值: <number> , none , auto 。这个属性的作用是在所用的字体不是创作人员的时维持清晰性。
(这一小节讲了个啥)
5.5 字形
font-style属性的作用十分简单:在 normal(常规)、italic(斜体) 和 oblique(倾斜)之间做出选择。
简单来说,斜体是一种单独的字型,各字母的构造有些改动,体现外观上的不同。衬线字体在这一点上体现的尤为明显。
除了字符有点斜之外,字符本身还可能会做调整。而倾斜体只是在竖直体的倾斜版本。
其实,不是每款字体都复杂到同时提供斜体和倾斜体,也很少有浏览器复杂到能区分二者之间的不同。
font-style 描述符 :用作描述符时,把指定的字型对应到指定的字形上。
<style> @font-face { font-family: "SwitzeraADF"; font-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;} /* 上述规则将使用"SwitzeraADF-Italic" 渲染h2 和 h3 元素,而不使用"SwitzeraADF-Regular" */ </style>
5.6 字体拉伸
有些字体族中的变体可能具有较宽或较窄的字母形式,这种变体存在的目的是在同一个字体族中提供瘦体和胖体。CSS提供了一个属性,用于选择这样的变体,如此便无需在font-family 声明中指定使用单独的字体族,这个属性是 font-stretch 。
仅当使用字体族中有宽体和窄体时,这个属性才起作用,而一般的字体族并没有这样的变体(如果有,字体族的价格往往不菲)。因此,这个属性的作用与 font-size 相差很大,后者可以随时随地改变字号。仅当使用的字体族中有加宽变体时, font-stretch: expanded 声明才起作用。
如果没有加宽变体,什么也不会发生,即仍然使用原生的字型。
font-stretch 描述符:作用是把不同宽度的字型分配给 font-stretch 属性允许取的不同宽度值。
5.7 字距调整
有些字体定义了字符之间相对位置的数据,即字距。不同的字符组合,字距是不同的。字距可以使用 font-kerning 属性呼出或禁止。
取值:auto , normal , none 。
none让用户代理忽略字体中的字距信息。
normal 的意思是让用户代理正常处理字距,即使用字体中的字距数据。
auto则把决定权交给用户代理,让用户代理选择最合适的处理方式,当然具体怎么做由所用的字体决定。
如果字体中没有字距数据, font-kerning 没有任何作用。
5.8 字体变形
除了字重,字形等之外,字体还有变形。变形信息内嵌在字型中。如果字型中有变形信息,可以通过 font-variant 属性调用。
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> <style> body{ font-size: 200%;} div{font-variant: small-caps;} /* 使用小号大写字母 */ p{font-variant: normal;}/* 表示普通形式 */ </style> </head> <body> <div>font-variant: small-caps;</div> <p>font-variant: normal;</p> </body> </html>
5.9、5.10 (暂省略)
5.11 font属性
font简写 - 我歌且谣 - 博客园 (cnblogs.com)
5.11.3 使用系统字体
如果你想让网页与用户的操作系统融为一体,可以在 font 声明中使用系统字体值。这样设定之后,元素上应用的是操作系统中控件的字号、字体族、字重、字形和变形。
可用的系统字体值如下:
caption : 用于说明文字的控件,如按钮。
icon : 标注图标。
menu : 在菜单中使用,即下拉菜单和菜单系列。
message-box :在对话框中使用。
small-caption : 用于标注小型控件。
status-bar : 用在窗口的状态栏中。
例如,你可能想把按钮的字体设成与操作系统中的按钮一样,比如说:
button { font: caption; }
使用这些值可以让web 应用看起来像用户操作系统的原生应用一样。
<!DOCTYPE html> <html lang="en"> <head> <title>Document</title> <style> div{margin: 200px;} button:first-child{font: caption;} </style> </head> <body> <div> <button>使用caption</button><br><br> <button>未用caption</button> </div> </body> </html>
5.12 字体匹配机制
CSS能选择字体族,字重和变体,这背后隐藏着字体匹配机制,匹配过程如下:
- 用户代理创建或访问字体属性数据库。这个数据库中有用户代理能访问到的全部字体的各个CSS属性。
- 用户代理把应用了字体属性的元素摘出来,构建显示元素所需的字体属性列表。
- 匹配字体时先看 font-stretch 属性。
- 然后再看 font-style 属性。
- 接下来匹配 font-weight 属性。
- 然后处理 font-size 。
- 如果第 2 步没有找到匹配的字体,用户代理在同一个字体族中选择替代字体,找到后回到第 2 步。
- 假设找到一个基本匹配的字体,但是字体没有显示元素所需的全部信息,那么用户代理回到第 3 步,搜索替代字体,然后再执行第 2 步。
- 最后,如果找不到匹配的字体,而且所有替代字体都试过了,用户代理将选择指定字体族中的默认字体,力争正确显示元素。