4.4 文字版式

现在该检验一下我们实际应用字体和文本样式的能力了。在本章最后这一节,我们要动手循序渐进地做三个网页排版的例子。

文字排版讲求匀称,一般是由看不见的网格,框定页面文字的走向和布局。匀称的版式可以增强页面的可读性。

下面我们先来看一个基本的、简单的例子。在这个例子中,我们先不用网格,只是基于元素中的字体大小按比例地设定元素间距。这个练习可以告诉你怎么高效地实现想要的效果。

4.4.1 简单的文本布局

我们在第1章就已经介绍过了,浏览器为标题、段落、列表及其他元素默认应用的字体大小并不一致,而且垂直外边距也太大。为了示范怎么覆盖默认样式,获得匀称的版面,需要以下包含常用文本元素的HTML标记。

  1. <article>
  2. <h1>CSS</h1>
  3. <p>CSS stands for Cascading Style Sheets. CSS controls the presentational aspects of your Web pages.</p>
  4. <h2>Block-Level Elements</h2>
  5. <p>Block-level elements stack down the page. They include:</p>
  6. <ul>
  7. <li><code>header</code></li>
  8. <li><code>section</code></li>
  9. <li><code>h1, h2, etc.</code></li>
  10. </ul>
  11. <h2>Inline Elements</h2>
  12. <p>Inline elements sit next to each other, if there is room. They include:</p>
  13. <ul>
  14. <li><code>img</code></li>
  15. <li><code>a</code></li>
  16. <li><code>em</code></li>
  17. </ul>
  18. <blockquote>
  19. <q>Typography maketh the Web site.</q><cite>CWS</cite>
  20. </blockquote>
  21. </article>

图4-16展示了以上标记在浏览器中的效果。

enter image description here图4-16 没有添加样式的标记没有什么吸引力

下面我们来写一些样式,让版面看起来更舒服。首先,去掉元素的外边距,设定主字体大小,为包含所有文本元素的article应用样式,从视觉上突出它作为容器的角色,然后将它在页面上居中。

  1. /*删除所有元素的外边距*/
  2. * {margin:0; padding:0;}
  3. /*设定主字体族和字体大小*/
  4. body {font:1.0em helvetica, arial, sans-serif;}
  5. /*居中显示盒子*/
  6. article {width:500px; margin:20px auto; padding:20px; border:2px solid #999;}

值为1.0emfont-size只是显式地声明了默认字体大小,并没有修改什么。但为了将来修改页面中所有文本的字体更方便,必须在font简写属性中同时设定字体大小,而且要使用相对单位em。

图4-17展示了此时在浏览器中看到的结果。

enter image description here图4-17 删除默认的外边距显著减少了内容的高度

接下来,需要巧妙地安排一下元素间的垂直距离。另外,去掉默认外边距后列表项目的符号也跑到了外面,这里一块儿修复。

  1. /*标题周围的空白*/
  2. h1, h2, h3, h4, h5, h6 {line-height:1.15em; margin-bottom:.1em;}
  3. /*文本元素周围的空白*/
  4. p, ul, blockquote {line-height:1.15em; margin-bottom:.75em;}
  5. /*缩进列表*/
  6. ul {margin-left:32px;}

enter image description here图4-18 为段落下方添加了空白

如图4-18所示,我们把所有元素的行高都缩小了,让它们只比文本稍微高一点点。为什么呢?因为line-height会平均分布在文本上下,而我只想通过下外边距在每个元素下方添加空白。但同时,还要留出少量行高,以防段落(和跨行的标题)中相邻的行紧挨上。

为此,这里只设定了两处外边距,而实际的空白要相对于元素的字体大小来计算。标题的下外边距非常小(等于各自字体大小的10%),因此后面的文本会离它很近。文本元素的下外边距大一些(等于各自字体大小的75%),以便布局中有较明显的空白。

最后,我想让各级标题也更均衡一些,保证较大的标题突出,最小的标题也不至于不明显,同时也增大了code元素的字体。

  1. /*调整标题文本*/
  2. h1 {font-size:1.9em;}
  3. h2 {font-size:1.6em;}
  4. h3 {font-size:1.4em;}
  5. h4 {font-size:1.2em;}
  6. h5 {font-size:1em;}
  7. h6 {font-size:.9em;}
  8. /*调整段落文本*/
  9. p {font-size:.9em;}
  10. /*调整代码文本(默认值太小了)*/
  11. code {font-size:1.3em;}

enter image description here图4-19 标题和代码都加大了,而且页面也更有层次感

这个例子虽然又简单又基础,但它却展示了如何通过最少量的文本样式来提高页面版式的专业水准和内容的可读性,最终结果如图4-19所示。下面我们再看看怎么借助网格来创造出更有吸引力的页面布局。

4.4.2 基于网格排版

借助网格可以保证布局匀称,同时让页面看起来也很流畅。因为本章主要介绍网页版式,所以我们只讨论借助网格创建垂直的文本流。

在下面的例子中,我会基于垂直的18像素网格来规划布局,并让页面中的每一个元素都按网格线对齐。还记得可以在元素的背景上添加图片吧,我们可以临时在body元素的背景上添加一张图片,让它为整个页面生成辅助线。

我使用Adobe Fireworks(你可以选择自己最称手的软件)创建了一个100×18像素的矩形,并在它的底部画了一条灰线。然后将其保存为.png格式(.jpg或.gif格式也没有问题),并命名为grid_18px.png.,图4-20展示了这张图片(为清楚起见,我把它放在了一个深色背景上)。

enter image description here图4-20 用作页面背景的小拼贴图,长方形底部有一条灰线

把这张图片放到body元素的背景上:

  1. /*添加网格线*/
  2. body {background-image:url(images/grid_18px.png);}

然后它就会像贴瓷砖一样“贴”满了整个页面,如图4-21所示。

enter image description here图4-21 为body元素应用横格背景,以便垂直排版文字

生成水平的网格背景后,就可以依照网格来定位文本元素了。

这个例子只使用了一些常见的文本元素,但只要理解了背后的原理,写出一个让HTML文本元素“对齐网格”的样式表一点也不难。而有了这样的样式表,整个网站的布局就有了基础。

这个例子包含如下所示的简单段落:

  1. <p>In traditional typography, text is composed…</p>

CSS规则如下:

  1. /*去掉所有元素的内边距和外边距*/
  2. * {margin:0; padding:0;}
  3. body {
  4. /*添加网格背景*/
  5. background-image:url(images/grid_18px.png);
  6. /*设定字体*/
  7. font:100% helvetica, arial, sans-serif;
  8. /*加宽左右外边距,得到一栏的雏形*/
  9. margin:0 40px 0;
  10. }
  11. p {
  12. /*设定字体大小*/
  13. font-size:13px;
  14. /*将行高设定为等于网格高*/
  15. line-height:18px;
  16. }

注意,这里把文本的line-height设定为网格间的距离——18像素。在去掉默认外边距和内边距的情况下,这样就可以确保每一行都相距18像素,如图4-22所示。

enter image description here图4-22 18像素的行高让文本行的间距与网格间距恰好一致

再给容器body元素添加4像素的内边距,以便把元素向下推到文本基线与网格对齐的位置。只要让第一个元素与网格对齐,其他元素就都能对齐了。实际上,我给body上方添加了22像素(4+18)的内边距,以便上方能有一定的空间:

  1. padding-top:22px;

之后,给段落添加一条声明:

  1. p {
  2. font-size:13px;
  3. line-height:18px;
  4. margin-bottom:18px;
  5. }

这条声明恰好能在每个段落之间加上一个空行。再加上一段文本,就能更清楚地看这两处修改的效果了(见图4-23)。

enter image description here图4-23 为body添加了内边距之后,文本与网格完美地对齐了

现在,文本与网格对齐了,段落之间的间距也合适了。接着要设定其他文本元素的字体大小。首先把h3设定为18像素,而为了让它恰好在网站中占一行,必须得把它的line-height也设定为18像素。为了测试,我们在两段之间加入一个标签。

  1. <p>In traditional typography, text is composed…</p>
  2. <h3>Type for Every Use</h3>
  3. <p>The ubiquity of type has led typographers…</p>

针对这个标题的CSS规则如下:

  1. h3 {font-size:18px; line-height:18px;}

enter image description here图4-24 h3元素的基线比网格线稍微低一点

如图4-24所示,标题的基线比网格低几个像素。然而奇怪的是,下方的段落并没有因此向下挪动相应距离。这是为什么呢?因为标题的line-height是正确的,只是由于它现在的字体大小以及字体的因素,导致文本在内部稍微有一点偏移。纠正这个问题的CSS如下:

  1. h3 {
  2. font-size:18px;
  3. line-height:18px;
  4. margin-top:-2px;
  5. margin-bottom:2px;
  6. }

enter image description here图4-25 少许上负外边距和同等数量的下正外边距把标题提升到了恰好与网格对齐的位置

上方的负外边距把文本向上拉,下方同样数量的正外边距用来抵消它,保证后面元素的位置不受影响(参见图4-25)。

我们还需要一种类似技巧来对齐比网格高的元素(通常是标题)。为此,要添加一个24像素的h1元素。显然,24像素的文本占据的空间比一行网格要高,因此给它设定的line-height是36像素,也就是两行网格的高度。然后,就是把h1元素放到它应该出现的地方——页面的开头。

  1. <h1>Typography</h1>
  2. <p>In traditional typography…</p>

当前给它设定的CSS如下:

  1. h1 {font-size:24px; line-height:36px;}

enter image description here图4-26 由于line-height等于两倍网格行高,所以标题没有在网格线上

这个占两行网格的大标题看起来不太舒服。如果把它移动到下方最近的线上,那么其字母下伸部分就会接触到段落文本,所以我要把它向上移动。经过一番试错,我决定把它向上移动13像素。

另一种思路是把标题文本的基线放在两行网格线之间一半的位置。那会实现一种不同的风格。不过,无论如何都要保证后面的元素与网格对齐。

  1. h1 {
  2. font-size:24px;
  3. line-height:36px;
  4. margin-top:-13px;
  5. margin-bottom:13px;
  6. }

这样,h1下方与文本之间就空出了一定距离(参见图4-27)。对于级别低一点的标题也可以应用同样的技巧,但我个人还是倾向于认为标题与其下方元素再接近一些才舒服。

enter image description here图4-27 h1元素的基线与网格线对齐了

在这个练习最后 ,我们再加几个不同字体大小的标题、一个无序列表和一个blockquote元素。看一看把网格去掉之后页面是什么样子。

这个练习的HTML代码可以在本书网站下载:http://www.stylinwithcss.com

  1. * {margin:0; padding:0;}
  2. body {font:100% helvetica, arial, sans-serif; backgroundimage: url(images/grid_18px.png); margin:0 20px 0;
  3. padding:21px;}
  4. p {font-size:14px; line-height:18px; margin-bottom:18px;}
  5. h1 {font-size:24px; line-height:36px; margin-top:-13px;
  6. margin-bottom:13px;}
  7. h2 {font-size:18px; line-height:18px; margin-top:-2px;
  8. margin-bottom:2px;}
  9. h3 {font-size:16px; line-height:18px; margin-top:-2px;
  10. margin-bottom:2px;}
  11. ul {margin-bottom:18px;}
  12. li {font-size:13px; list-style-type:none; padding:0 20px;
  13. line-height:18px;}
  14. a {color:#777; text-decoration:none;}
  15. blockquote {font-size:12px; line-height:18px; padding-top:
  16. 2px; margin-bottom:16px;}

enter image description here图4-28 基于18像素网格的页面布局

如图4-28所示,利用网格辅助排版之后的布局还是不错的。从技术角度讲,如果你基于网格为一个网站设计了版式,而后将其交给了其他人维护,那这个网站的版式就能始终保持一致,无论页面中包含什么元素,以及以什么顺序包含这些元素。

4.4.3 经典的排版练习

本章最后,我们节选The Hound of the Baskervilles(《巴斯克维尔庄园的猎犬 》)1中的部分文本(为了示例需要进行了删减)来做一个排版练习。这个练习将会用到本章讲过的很多字体和文本属性。完成这个练习后,你就能掌握实现专业排版的很多技术,包括使用HTML实体、调整字母和单词间距、首字下沉、垂直网格(这一次是24像素)以及可下载字体。

1《巴斯克维尔庄园的猎犬》是阿瑟·柯南·道尔最得意的长篇杰作之一,堪称福尔摩斯探案故事的代表作。——译者注

示例的HTML标记非常简单,只有两个标题、几个段落和一个块引用。

  1. <h2>an excerpt from</h2>
  2. <h1>The Hound of the Baskervilles</h1>
  3. <p>Holmes stretched out his hand for the manuscript and flattened it upon his knee. &ldquo;You will observe, Watson, the alternative use of the long s and the short. It is one of several indications which enabled me to fix the date.&rdquo; At the head was written: &ldquo;Baskerville Hall,&rdquo; and below in large, scrawling figures: &ldquo;1742.&rdquo;</p>
  4. <p>&ldquo;It appears to be a statement of some sort.&rdquo;</p>
  5. <p>&ldquo;Yes&mdash;it is a statement of a certain legend which runs in the Baskerville family.&rdquo;</p>
  6. <blockquote>
  7. <q>Of the origin of the Hound of the Baskervilles there have been many statements, yet as I come in a direct line from Hugo Baskerville, and as I had the story from my father&hellip;</q>
  8. </blockquote>
  9. <p>When Dr. Mortimer had finished reading this singular narrative he pushed his spectacles up on his forehead and stared across at Mr. Sherlock Holmes.</p>

这段标记包含了几个HTML实体,它们代表的是几种标点符号。其中,有表示对话开始的左双引号(&ldquo;) 、表示对话结束的右双引号(&rdquo;)、表示省略的省略号(&hellip;)和表示暂停或代替括号的破折号(&mdash;)。

HTML实体引用

以下网站中列出了HTML实体:

上面第一个链接中既包含HTML实体值,也包含实体需要作为::before::after伪元素内容时的十六进制值。举个例子,如果你想在伪元素中添加十六进制值&#x201C;(左双引号),则需要改写成如下形式:

e::before {content:"\201C";}

就是在数字前面加了一个反斜杠。相应地,右双引号的十六进制值改写后是\201D

在HTML标记中,必须把所有和号(&)和小于号(<)都替换成相应的HTML实体,也就是&amp;&lt;。因为“&”是实体的第一个字符,而“<”是HTML标签的第一个字符,它们都有特殊含义。如果不替换的话,浏览器一看到它们就会当成实体和标签来解释后面的内容。

第一步:设定字体和底层网格

这两段文本使用的主字体是FontSquirrel提供的字体Crimson Roman。我下载了相应的字体包,放在了我Web服务器上(在编写代码的过程中,我在本地也保存了一份),然后把其中的@font-face规则添加到了样式表中。之后,就可以在font-family属性中引用该字体了。

  1. @font-face {
  2. font-family:'CrimsonRoman';
  3. src: url('fonts/Crimson-fontfacekit/Crimson-Roman-webfont.
  4. eot');
  5. src: url('fonts/Crimson-fontfacekit/Crimson-Roman-webfont.
  6. eot?#iefix') format('embedded-opentype'),
  7. url('fonts/Crimson-fontfacekit/Crimson-Roman-webfont.
  8. woff') format('woff'),
  9. url('fonts/Crimson-fontfacekit/Crimson-Roman-webfont.
  10. ttf') format('truetype'),
  11. url('fonts/Crimson-fontfacekit/Crimson-Roman-webfont.
  12. svg#CrimsonRoman') format('svg');
  13. font-weight: normal;
  14. font-style: normal;
  15. }
  16. * {margin:0; padding:0;}
  17. body {
  18. font-family:"CrimsonRoman", georgia, times, serif;
  19. background-color:#fff;
  20. margin:0 10% 0;
  21. background-image:url(grid_24px.png);
  22. }

按照我们的标准工作流程,这里先去掉了所有外边距和内边距,设定了主字体,又添加了左、右外边距,还为对齐文本临时添加了网格,结果如图4-29所示。

enter image description here图4-29 文本和网格已经就位,就等对齐了

第二步:设计标题

排版资源

http://ilovetypography.com 在这个网站上,你可以跟着设计师John Boardley一起深思,欣赏每一页中别具一格的排版。

http://www.thinkingwithtype.com 这是Thinking with Type一书的网站,作者Ellen Lupton。网站中展示了很多漂亮又经典的版式,还包含一些字体及字体族的信息。

http://webtypography.net 这个站点自称为The Elements of Typographic Style Applied to the Web—A practical guide to web typography。跟随网站的目录,可以找到各种常用的排版知识和技巧。

下面我们就从上到下,对齐页面中的每一个元素。第一行的副标题应该与第二行的主标题形成对比,因为主标题要使用手写字体,所以副标题就设定成间距较宽的小型大写字母。

  1. body {
  2. font-family:"CrimsonRoman", georgia, times, serif;
  3. background-color:#fff;
  4. margin:29px 10% 0;
  5. background-image:url(grid_24px.png);
  6. }
  7. h2 {
  8. font-size:18px;
  9. line-height:24px;
  10. font-weight:bold;
  11. text-align:center;
  12. font-variant:small-caps;
  13. word-spacing:.5em;
  14. letter-spacing:.6em;
  15. }

首先,我们用font-variant把副标题转换成小型大写字母,然后应用word-spacingletter-spacing得到预期结果,如图4-30所示。

enter image description here图4-30 副标题不仅与网格对齐,而且也应用了字体和文本属性

接下来,打开Google Web Fonts网站,找到一种名为Pinyon的手写体,这种字体与主标题挺配的。然后,把Google Web Fonts生成的<link>标签复制粘贴到HTML文档的<head>标签里,这样就能在font-family声明中引用这种字体了。这里仍然需要用到图4-25中曾用过的“负/正外边距”技巧,把主标题移动到恰好与网格对齐,得到的效果如图4-31所示。

  1. <link href='http://fonts.googleapis.com/css?family=Pinyon+Script' rel='stylesheet' type='text/css'>
  2.  
  3. h1 {
  4. font-size:60px;
  5. line-height:96px;
  6. font-family:"Pinyon Script", cursive;
  7. margin:4px 0 -4px;
  8. text-align:center;
  9. font-weight:normal;
  10. position:relative;
  11. }

line-height是网格宽度的4倍。

enter image description here图4-31 主标题已经应用了样式,并与网格对齐了

第三步:设计段落和引用

第一段的位置有点高,因此我们设定它的字体大小,以及——更重要的是设定它的行高。

  1. p {font-size:18px; line-height:24px;}

enter image description here图4-32 通过设定line-height让段落与网格对齐

前三段虽然对齐了,但后面的段落没有,这是因为第三段后面的引用(blockquote)也需要对齐。blockquote中的文本包含在一个行内元素q(quote)中,这个元素的默认样式是在文本开头和末尾加上引号。在此,我们来缩进blockquote,但在其q子元素上设定字体大小和行高,因为它才是包含文本的元素:

  1. blockquote {margin:0px 20%;}
  2. q {font-size:18px; font-style:italic; line-height:24px;}

enter image description here图4-33 引用与网格也对齐了

缩进引用并将文本变成斜体为页面增加了变化。另外,你看到了吗,在blockquote就位后,它后面的段落自然也就与网格对齐了。

第四步:首字下沉效果

现在,我们打算给第一段添加一个独特的首字下沉效果。所谓首字下沉,就是将段落开头的第一个字母变大,然后根据该字母与段落首行的位置关系,又可以分几种不同的风格。在这里,我们想让字母的顶部与段落首行顶部对齐,让字母的底部与段落第三行的基线对齐。

或许你以前也见过这种效果,而那些效果中的首字母都被包含在一个span元素里。这种做法对于从内容管理系统中动态取文本的网页并不适用。所以,我们这里要介绍一种不用修改标记的技巧。

为此,需要选择h1标题后面第一个段落的第一个字母,而组合使用紧邻同胞选择符+::first-letter伪元素可以做到。选择了第一个字母后,再增大字体并浮动它:

  1. h1 + p::first-letter {
  2. font-family:times, serif;
  3. font-size: 90px;
  4. float:left;
  5. border:1px solid;
  6. }

enter image description here图4-34 这里显示边框是为了看清楚首字母从段落文本中继承的line-height有多高

首字母增大了,但位置不对。由于我们实际上是想调整盒子的大小和位置,所以首字母的边框在此可以作为辅助。而边框告诉我这个盒子只大到了让两行文本绕排,原因是首字母继承了段落的行高和对齐方式。我们需要设定这个伪元素的line-height,让它的盒子能包含首字母。

我们把line-height设定为小于1的值,以便元素盒子紧紧包住首字母,而不会强迫段落第四行也绕排。

  1. h1 + p::first-letter {
  2. font-family:times, serif;
  3. font-size:90px;
  4. float:left;
  5. line-height:.65;
  6. border:1px solid;
  7. }

enter image description here图4-35 元素盒子紧紧包住首字母

如图4-35所示,增大盒子的line-height后,第三行也绕排了。现在,只要再给这个元素顶部添加一点内边距,就可以让字母的底部与段落第三行的基线对齐了。

  1. h1 + p::first-letter {
  2. font-family:times, serif;
  3. font-size:-90px;
  4. float:left; line-height:.65;
  5. padding:.085em 3px 0 0;
  6. }

我还添加了3像素的右内边距,以便首字母与段落之间空开一点距离。当然,边框也没用了,把它去掉之后的效果如图4-36所示。

enter image description here图4-36 完成后的首字母下沉效果

第五步:设计第一行

首字母下沉效果做完了。可是,我希望大号首字母到小号正文之间有一个过渡,所以需要把段落第一行的文本变成小型大写字母。

  1. h1 + p::first-line {
  2. font-variant:small-caps;
  3. letter-spacing:.15em;
  4. }

enter image description here图4-37 段落第一行变成了小型大写字母

这一次同样使用了紧邻同胞选择符,但组合的是::first-line伪元素,实现了第一行字形的转换。使用伪元素而不是额外加标签的好处在于,当行的长度改变时,大写字母的效果会随之扩展。图4-37展示了这行大写字母在首字母与正文之间起到的衔接作用。

第六步:最后的修饰

段落之间没有足够的间距,让人很难看出它们的开头在哪里。为了与这本书的版式保持一致,我们不给段落之间加空白,而是缩进跟在其他段落后面的每一段,作为一组段落起头的一段不缩进。此外,引用内容两端的引号也太难看,所以要在<q>标签上应用::before::after伪元素,插入Crimson字体的引号。最后,再从body元素中去掉网格背景(让它不再显示)。

  1. /*只缩进跟在段落后面的段落*/
  2. p + p {text-indent:14px;}
  3. /*引用内容前面的引号*/
  4. q::before {content:"\201C"}
  5. /*引用内容后面的引号*/
  6. q::after {content:"\201D"}

这几条声明都有必要解释一下。选择要缩进的段落使用的是紧邻同胞选择符,以保证只有段落后面的段落才会缩进。“When Dr. Mortimer…”开头的那一段,因为前面是一个blockquote,不是段落,所以就没有缩进,而且它也十分明显就是一个段落的开头(参见图4-38)。

使用::before::after伪元素给引用内容添加引号时使用的是十六进制值。在这里不能给content属性设定常规的HTML实体,只能使用十六进制实体值,而且只能是改写后的形式。关于HTML实体引用的详细介绍,请参考本节开头的那个附注栏。

enter image description here图4-38 完成后的页面

经过最后的修饰,这个经典版式设计终于完成了。对于节选的那么几段文本来说,好像工作量还不小。不过别忘了,这些样式其实是很容易应用给整整一本书的。