CSS权威指南(第四版)读书笔记——第5章 字体之一

前端技术 everyinch 1683℃ 0评论

CSS1规范写于1996年,“Font Properties”(字体属性)一节的开头是这样说的,“设置字体属性是样式表最常见的用途之一。”这么多年过去了,这句话仍无法推翻。

CSS2开始支持使用@font-face下载指定的自定义字体,不过直到2009年前后这个功能才以一致的方式被广泛支持。

然而,要注意,这并不表明你能完全控制字体。如果字体下载失败,或者字体的格式不被用户的浏览器支持,那么文本将使用后备字体显示。

5.1 字体族

我们熟知的“字体”通常包含多个变体,分别针对粗体、斜体等。例如你可能熟悉(至少听说过)的Times字体,其实它有多种变体,包括TimesRegular、TimesBold、TimesItalic、TimesBoldItalic等。Times的这些变体各自都是一个字型(font face),我们通常说的Times,其实是这些不同字型的统称。也就是说,Times其实是一个字体族(font family),而不是一个字体。大多数人都会把字体理解为单个实体。

为了覆盖所有情况,CSS定义了五种通用字体族:

衬线字体:这种字体中的字形宽度各异,而且有衬线。因为字体中不同字符的尺寸不同,所以宽度才有差异。

无衬线字体:这种字体中的字形宽度各异,而且无衬线。

等宽字体:等宽字体中的字形宽度一样。一般用于显示编程代码或表格数据。这种字体中的各个字符在横向上所占的空间是一样的;因此,尽管小写字母i和小写字母m这两个字母本身的宽度不同,但使用等宽字体时二者所占的横向空间一样大。

草书字体:这种字体尝试模仿人类笔迹或手写体。通常,这种字体在笔划末端有较大的花饰,而且比衬线字体华丽。

奇幻字体:这种字体(有时也叫“装饰”字体或“展示”字体)还真没什么统一的特征,不过可以确定的是,无法将其划归到其他类别中。

5.1.1使用通用字体族

字体族使用font-family属性声明。

font-family:[ <family-name> | <generic-family> ] #

<family-name> = arial | georgia | verdana | helvetica | simsun and etc.

<generic-family> = cursive | fantasy | monospace | serif | sans-serif

默认值:由user agent决定

适用于:所有元素

继承性:有

动画性:否

计算值:指定值

媒 体:视觉

如果想让一个文档使用无衬线字体,但不介意具体使用哪一款,可以这样声明:

body {font-family: sans-serif;}

利用这些通用字体族,创作人员可以编写十分复杂的样式表。下述规则得到的结果如图5-1所示。

body {font-family: serif;}

h1, h2, h3, h4 {font-family: sans-serif;}

code, pre, tt, kbd {font-family: monospace;}

p.signature {font-family: cursive;}

此时,文档中的大部分内容将使用衬线字体(例如Times),不过class为signature的段落将使用草书字体(例如Author)渲染。一级标题到四级标题将使用无衬线字体(例如Helvetica),而code、pre、tt、和kbd元素将使用等宽字体(例如Courier)。

图5-1:使用不同的字体族

5.1.2指定字体族

假设现在想让所有h1都使用Georgia字体显示。实现这一需求最简单的规则如下:

h1 {font-family: Georgia;}

这样声明后,用户代理会使用Georgia字体显示文档中的所有h1,如图5-2所示。

图5-2:使用Georgia字体显示hl元素

鉴于此,笔者强烈建议始终在font-family规则中指定通用字体族。这样做相当于提供一种后备机制,在用户代理找不到匹配的字体时,选择一个字体代替。下面再举几个例子:

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;}

对字体熟悉的人,可能记着多款相似的字体。假如我们想让文档中的所有段落都使用Times显示,不过Times New Roman、Georgia、New Century Schoolbook和New York也是可以接受的选择(这些都是衬线字体)。首先,定好各字体的顺序,然后一个接一个,以逗号分开:

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

用户代理会按照所列的顺序查找字体。

使用引号

在font-family声明中,如果字体名称中有一个或多个空格(例如“New York”),或者字体名称中有符号(例如#或$),建议使用引号。因此,名为Karrank%的字体就应该放在引号里:

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

如果没有引号,用户代理可能会忽略那个字体名称,然后接着处理规则后面的部分。

使用的引号既可以是单引号,也可以是双引号。注意,如果把font-Family规则放在style属性中(一般不应该这么做),使用的引号要与属性使用的不同。因此,如果font-family规则放在双引号里,那么规则内部就要使用单引号,如下所示:

p {font-family: sans-serif;}   /* 设置段落使用无衬线字体 */

<!– the next example is correct (uses single-quotes) –>

<p style=”font-family: ‘New Century Schoolbook’, Times, serif;”>…</p>

<!– the next example is NOT correct (uses double-quotes) –>

<p style=”font-family: “New Century Schoolbook”, Times, serif;”>…</p>

此时使用双引号的话,将与属性的句法冲突,如图5-3所示。

图5-3:使用错误的引号导致的问题

5.2使用@font-face

@font-face的作用是让你在设计中使用自定义的字体。这个特性首次出现在CSS2中,不过直到21世纪头十年的后半期才实现。

假设你想使用的字体没有广泛安装,而是个十分特别的字体。借助@font-face的魔力,你可以定义一个专门的字体族名称,对应于服务器上的一个字体文件。用户代理将下载那个文件,使用它渲染页面中的文本,就好像用户的设备中安装了那个字体一样。下面举个例子:

@font-face {

font-family: “SwitzeraADF”;

src: url(“SwitzeraADF-Regular.otf”);

}

用户代理见到-font-family: SwitzeraADF声明后,会加载对应的.otf文件,然后使用它渲染文本。

5.2.1必须的描述符

定义字体的全部参数都在@font-face{}结构中编写。这些参数称为描述符(descriptor),与属性十分相似,格式为descriptor: value;。

描述符中有两个是必需的: font-family和src。

font-family

取值:<family-name>

初始值:未定义

src

取值:[ [ <uri> [format(<string>#)]?] | <font-face-name> ]#

src的作用不言而喻:为定义的字型提供一个或多个源。如果有多个源,之间以逗号分隔。字型的源可以指向任何URI,不过有个限制:字型必须与样式表同源。

其实,@font-face做的是低层定义,是为字体相关的属性(如font-family)服务的。通过描述符font-family: “SwitzeraADF”; 定义一个字体族名称之后,用户代理的字体族名称表中便会出现”SwitzeraADF”条目,与Helvetica、Georgia、Courier等具有同等地位,可以在font-family属性的值中引用:

@font-face {

font-family: “SwitzeraADF”;    /* 描述符 */

src: url(“SwitzeraADF-Regular.otf”);

}

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

注意,font-family描述符的值和font-family属性中出现的那个字体族名是一样的。只要成功下载了字体文件,而且文件的格式是用户代理支持的,那个字体就会像其他字体一样用于渲染文本,如图5-4所示。

图5-4:使用一款下载的字体

类似地,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()还能为不带有常规扩展名的字体文件指定格式,以防用户代理不识别:

@font-face {

font-family: “SwitzeraADF”;

src: url(“SwitzeraADF-Regular.otf”) format(“opentype”),

url(“SwitzeraADF-Regular.true”) format(“truetype”);

}

可用的格式值见表5-1(截至2017年年末)。

表5-1:支持的字体格式值

格式
embedded-opentype EOT(Embedded Opentype)
opentype OTF(OpenType)
svg SVG(Scalable Vector Graphics)
truetype TTF(TrueType)
woff WOFF(Web Open Font Format)

除了使用url()和format()组合之外,还可以使用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”);

}

这里,用户代理先检查设备中是否有名为“Switzera-Regular”或“SwitzeraADF-Regular”的字体族,如果有,使用SwitzeraADF这个名称指代本地安装的字体,如果没有,尝试从远端下载url()中指定的字体文件。

注意,借助这个功能可以为本地安装的字体自定义名称。例如,可以像下面这样为Helvetica(没有这个字体的话,尝试Helvetica Neue)起个简短的名称:

@font-face {

font-family: “H”;

src: local(“Helvetica”), local(“Helvetica Neue”);

}

只要用户的设备中安装有Helvetica,前三级标题便将使用Helvetica渲染。

万全之策

@font-face有个棘手的问题要解决:不同时代的不同浏览器支持不同格式的字体(从表5-1中那些可下载的字体格式可见一斑)。为了尽量涵盖较广的场景,应该使用能确保万全的@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”);

}

下面详细说明。开头的部分,即指定font-family名称那一行无需过多解释。随后的两行:

src: url(“SwitzeraADF-Regular.eot”);

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

这两行为支持EOT (Embedded OpenType)格式的浏览器(IE6-IE9)提供EOT文件。前一行针对“兼容模式”下的IE9,后一行针对IE6-IE8。

url(“SwitzeraADF-Regular.woff”) format(“woff”),

这一行为支持Web Open Font Format的浏览器(包含多数现代浏览器)提供.woff文件。其实,至此已经涵盖大多数桌面用户了。

url(“SwitzeraADF-Regular.ttf”) format(“truetype”),

这一行为多数iOS和Android设备提供所支持的字体格式,涵盖了多数手持设备用户。

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

最后一行提供只有旧iOS设备支持的字体格式,涵盖余下的多数手持设备用户。

5.2.2其他字体描述符

除了必须的font-family和src描述符,还有几个可选的描述符用于为字型指定属性值。与font-Family一样,这些描述符也对应于现有的CSS属性(本章后文说明),控制着用户代理相应属性的处理方式。见表5-2。

表5-2:字体描述符

描述符 默认值 说明
font-style normal 区分常规、斜体和倾斜字型
font-weight normal 分不同的字重(例如加租)
font-stretch normal 区分不同的字符宽度(例如紧缩和加宽)
font-variant normal 区分众多字形变体(例如小号大写字母),在很多方面与css中的font-feature-settings很像
font-feature-settings normal 直接访问OpenType的低层特性(例如启用连字)
unicode-range U+0-10FFFF 定义指定字体中可用的字符范围

限制字符范围

有一个字体描述符没有对应的CSS属性(与表5-2中的其他描述符不同),即unicode-range。这个描述符用于指定自定义字体可以应用到哪些字符上。使用符号字体,或者想确保只有特定语言使用指定字型时用得到这个描述符。

unicode-range

取值<urange>#

初始值U+0-10FFFF

默认情况下,这个描述符的值涵盖全部Unicode字符。这表明,只要字体中有某个字符的字形,就能用它渲染那个字符。而有时我们想使用特定的字型渲染特定的内容。下面是从CSS Fonts Module Level 3规范中摘取的两个例子:

unicode-range: U+590-5FF;  /* 希伯来语字符 */

unicode-range: U+4E00-9FFF, U+FF00-FF9F, U+30??;  /* 日本汉字,平假名,片假名 */

第一个例子只指定了一个范围,从Unicode码位590~5FF。这个范围是希伯来语字符。因此,创作人员可以指定一个希伯来语字体,限制它只用于渲染希伯来语字符,即使字型中还包括其他码位的字形:

@font-face {

font-family: “CMM-Ahuvah”;

src: url(“cmm-ahuvah.otf” format(“opentype”);

unicode-range: U+590-5FF;

}

第二个例子指定了多个范围,以逗号分隔,涵盖所有日语字符。里面奇怪的u+30??值是unicode-range允许使用的特殊格式,问号是通配符,意思是“任何数字”。因此,U+30??等效于U+3000-30FF。unicode-range的值中只允许使用问号这一个“特殊的”字符。

范围必须从小到大,反过来(例如U+400-300)会导致解析错误而被忽略。除了范围之外,还可以声明单个码位,例如U+221E。单个码位通常与其他码位和范围结合起来使用,比如像下面这样:

unicode-range: U+4E00-9FFF, U+FF00-FF9F, U+30??, U+A5;

/* 日本汉字,平假名,片假名,外加货币符号 */

可以指定一个码位,让指定的字体渲染唯一的字符。

@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 */

}

第一个规则没有指定Unicode范围,因此始终下载,除非页面中恰巧什么字符也没有(不是不可能)。根据第二个规则,仅当页面中有指定Unicode范围内的字符时才下载myfont-cyrillic.otf。第三个规则一样,不过是当页面中有基本的算术运算符时才下载。

5.2.3组合描述符

我们可以把多个描述符组合在一起为字型设定不同的属性。以下面三个字型设定规则为例:

@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”);

}

这里我们明确列出了所需的描述符,即便使用默认值,也没有省略。把值为normal的描述符去掉之后,效果完全一样:

@font-face {

font-family: “SwitzeraADF”;

src: url(“SwitzeraADF-Regular.otf”) format(“opentype”);

}

@font-face {

font-family: “SwitzeraADF”;

font-weight: bold;

src: url(“SwitzeraADF-Bold.otf”) format(“opentype”);

}

@font-face {

font-family: “SwitzeraADF”;

font-style: italic;

src: url(“SwitzeraADF-Italic.otf”) format(“opentype”);

}

在这三个规则中,所有font-stretch的值都是normal,而font-weight和font:-style的值各异。如果想让加粗斜体字不拉伸呢?

@font-face {

font-family: “SwitzeraADF”;

font-weight: bold;

font-style: italic;

font-stretch: normal;

src: url(“SwitzeraADF-BoldItalic.otf”) format(“opentype”);

}

如果想得到紧缩的加粗斜体呢?

@font-face {

font-family: “SwitzeraADF”;

font-weight: bold;

font-style: italic;

font-stretch: condensed;

src: url(“SwitzeraADF-BoldCondItalic.otf”) format(“opentype”);

}

如果想得到紧缩的正常字重斜体呢?

@font-face {

font-family: “SwitzeraADF”;

font-weight: normal;

font-style: italic;

font-stretch: condensed;

src: url(“SwitzeraADF-CondItalic.otf”) format(“opentype”);

}

可行性还有很多,我们就此打住。如果把所有取值为normal的描述符都去掉,得到的结果如下,效果如图5-5所示。

@font-face {

font-family: “SwitzeraADF”;

src: url(“SwitzeraADF-Regular.otf”) format(“opentype”);

}

@font-face {

font-family: “SwitzeraADF”;

font-weight: bold;

src: url(“SwitzeraADF-Bold.otf”) format(“opentype”);

}

@font-face {

font-family: “SwitzeraADF”;

font-style: italic;

src: url(“SwitzeraADF-Italic.otf”) format(“opentype”);

}

@font-face {

font-family: “SwitzeraADF”;

font-weight: bold;

font-style: italic;

src: url(“SwitzeraADF-BoldItalic.otf”) format(“opentype”);

}

@font-face {

font-family: “SwitzeraADF”;

font-weight: bold;

font-stretch: condensed;

src: url(“SwitzeraADF-BoldCond.otf”) format(“opentype”);

}

@font-face {

font-family: “SwitzeraADF”;

font-style: italic;

font-stretch: condensed;

src: url(“SwitzeraADF-CondItalic.otf”) format(“opentype”);

}

@font-face {

font-family: “SwitzeraADF”;

font-weight: bold;

font-style: italic;

font-stretch: condensed;

src: url(“SwitzeraADF-BoldCondItalic.otf”) format(“opentype”);

}

图5-5:使用不同的字型

分享&收藏

转载请注明:陈童的博客 » CSS权威指南(第四版)读书笔记——第5章 字体之一

喜欢 (14)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
'; } if( dopt('d_footcode_b') ) echo dopt('d_footcode'); ?>