当前内容所在位置
- 第一章 层叠、优先级与继承
- 第二章 相对单位
- 2.1 相对单位的威力
- 2.1.1 响应式设计的兴起
- 2.2 em 与 rem
- 2.2.1 使用 em 定义字号
- 2.2.2 使用 rem 设置字号
- 2.3 告别像素思维 ✔️
- 2.4 视口的相对单位
- 2.5 无单位的数值与行高
- 2.6 自定义属性
- 2.7 本章小结
2.3 告别像素思维
过去常见的一种设计样式的做法(pattern),更准确地说是反常规的做法(antipattern),是将页面根元素的字号设为 0.625em
或 62.5%
;于是浏览器的默认字号就从 16px
缩小到了 10px
。这种做法看似简化了数学运算——当设计师说字号为 14px
,您只要在心中轻松除以 10,再让字号为 1.4rem
即可,顺便还兼顾了相对单位,例如:
html {
font-size: 0.625em;
}
但我不推荐这样做。
这么做一开始可能很方便,但存在两个缺点。首先是会导致大量冗余的样式代码。10px
用于文字还是太小了,因此只好在页面各处做补救:段落看着小,改到 1.6rem
;侧边栏感觉也小,就再来个 1.6rem
;貌似超链接也要 1.6rem
……这样一来,代码出错的概率就更大、今后更新样式要改的地方就更多、样式表也会变得更臃肿。
第二,这么做本质上还是像素思维。虽说代码写的是 1.6rem
,但脑子里仍然想的是 16px
。在响应式网页上,您需要习惯“模糊(fuzzy)”值:1.2em
究竟是多少像素并不重要;重要的是它比继承的字号大那么一点(即 20%);就算不是想要的大小,改改就是了,反复试错,直到满意为止。其实用像素的话也是这么个过程。
使用 em
时很容易陷入具体尺寸的泥沼,纠结于元素计算后的具体像素,尤其像字号这类;为了揪出 em
值的精确大小,您很可能会在无穷无尽的乘法、除法间反复横跳,直到抓狂。与其如此狼狈,不如听我一句劝,首先养成使用 em
的习惯。如果用惯了像素,切换到 em
肯定需要反复练习,但这一切都是值得的。
这并不是说您今后再也不能使用像素了。在和设计师打交道时,适当用一些具体的像素值进行交流也是无可厚非的;在项目初期,也需要确定基本的字号(通常是些标题和脚注的常用字号)。这时用绝对数值来讨论尺寸大小也更通俗易懂。
将大小转换为 rem
值需要做算术题,记得随手备个计算器。给根节点一个字号,也就定义了单位 rem
的大小。自此之后,像素应该仅限于在少数特殊情况下使用,而不能随处可见。
本章还会继续提到像素,这不仅有利于演示相对单位的行为方式,同时也可以帮您习惯 em
的计算。本章过后,将主要使用相对单位来讨论字号。
2.3.1 设置一个合理的默认字号
假设您希望默认字号为 14px
,那么就不必先给整个页面一个 10px
的默认字号然后再覆盖掉;直接将根元素的字号设为 14px
即可。期望的值除以继承值(此时为浏览器的默认字号)为 14/16
,等于 0.875
。在这里使用 em
既调整了默认字号,同时又尊重了用户的字体设置。
将以下代码添加到新样式表的顶部,以便在它基础上设计样式。这样就设置了根节点(<html>
)的默认字体。
代码清单 2.9 设置真正的默认字号
:root { /* 或使用 HTML 选择器 */
font-size: 0.875em; /* 14/16 (期望的px / 继承的px) = 0.875 */
}
现在页面上已经有了想要的字号,就不必在其他地方画蛇添足了;要改也只改和设计的默认字号不一致的地方,例如标题。
接下来创建一个如图 2.7 所示的面板。需要基于 14px
的字号,利用相对单位来实现。
图 2.7 使用相对单位和继承的字体大小创建的示例面板
该面板的 HTML 标记如下。添加到示例页:
代码清单 2.10 面板的 HTML 标记
<div class="panel">
<h2>Single-origin</h2>
<div class="panel-body">
We have built partnerships with small farms around the world to
hand-select beans at the peak of season. We then carefully roast
in <a href="/batch-size">small batches</a> to maximize their
potential.
</div>
</div>
以下是相应的样式代码:用 em
设置内边距和圆角半径,用 rem
设置标题字号,再用 px
设置边框。更新到您的示例样式表中:
代码清单 2.11 使用相对单位的面板样式
.panel {
/* 用 em 设置内边距和圆角 */
padding: 1em;
border-radius: 0.5em;
/* 用 1px 添加一个细边框 */
border: 1px solid #999;
}
.panel > h2 {
margin-top: 0; /* 移除面板顶部的多余空间,后续第3章详述 */
font-size: 0.8rem; /* 用 rem 设置标题字号 */
font-weight: bold;
text-transform: uppercase;
}
代码清单 2.14 给面板四周添加了一个细边框,并给标题指定了样式。该标题虽然字号偏小、但做了字体加粗和内容全大写处理。(如果设计需要的话,可以改为更大的字号,或者换用其他字体)。
第二个选择器中的 >
是一个 直接后代组合器(direct descendant combinator);它表示选择器中的两元素间存在直接父子关系。此时,该选择器将选中任意做 .panel
元素直接子元素的 h2
元素。(有关选择器和组合器的完整参考资料,参见 附录 A。)
在代码清单 2.10 中,给面板主体添加 panel-body
类只是为了明确含义,在 CSS 中并未用到。因为该元素已经继承了根元素的字号,渲染出来就是期望的效果,无需再变更。
2.3.2 构造响应式面板
更进一步地说,我们甚至可以基于屏幕尺寸,用 媒体查询 来改变根元素的字号。
媒体查询要用到 @media
规则,用于设置仅满足特定屏幕尺寸或媒体类型(例如打印机或屏幕)下的样式。它是响应式设计的核心要素。面板将根据用户屏幕的大小渲染出不同的尺寸(如图 2.8 所示)。
图 2.8 不同屏幕尺寸下的响应式面板:300px(左上)、800px(右上)、1440px(底部)
要查看页面效果,按如下代码更新样式:
代码清单 2.12 响应式的基础字号
:root {/* 作用于所有屏幕,但在会被更大屏幕的样式覆盖 */
font-size: 0.85em;
}
@media (min-width: 800px) {/* 仅适用于 800px 及以上屏幕,并覆盖之前的值 */
:root {
font-size: 1em;
}
}
@media (min-width: 1200px) {/* 仅适用于 1200px 及以上的屏幕,覆盖前面的两个值 */
:root {
font-size: 1.15em;
}
}
上述代码的第一个规则集指定了一个较小的默认字号,这也是我们希望在小屏幕上显示的字号;然后利用媒体查询技术,分别在 800px
和 1200px 及以上
的宽屏上依次逐渐增大字号来覆盖掉默认的字号值。
通过给页面根元素设置不同字号,我们响应式地重新定义了整个页面 em
和 rem
的含义。也就是说,即使不直接修改面板样式,它也是响应式的。在小屏幕上,比如智能手机上,字体会被渲染得更小(13.6px
),内边距和圆角半径也相应较小。而在宽度大于 800px
和 1200px
的大屏上,组件字号会相应地分别放大到 16px
和 18.4px
。缩放浏览器窗口可以看到这些变化。
如果足够严谨,整个页面的样式都像这样使用相对单位来定义,那么页面就会根据用户浏览器窗口的大小整体缩放。这可以成为设计响应式策略的重要组成部分。靠近样式表顶部的这两个媒体查询,可以极大减少后续 CSS 代码中媒体查询的数量。如果是用像素来定义的,就没那么容易实现了。
同样,如果后来发觉网站上的字体太小或太大,这时仅需改动一行代码就能整体切换字号,进而不费吹灰之力影响整个页面。
2.3.3 缩放单个组件
您还可以通过 em
来单独缩放某个页面组件,比如有时可能需要让同一个组件在页面的某些位置渲染出一个更大的版本。还是用之前的面板来举例说明。首先给面板添加一个 large
类:<div class="panel large">
。
图 2.9 展示了普通面板和大尺寸面板的区别。效果类似于响应式面板,但这两种尺寸都可以同时在同一页面中渲染出来:
图 2.9 ems 定义的面板可以通过增大字号来放大
下面对定义面板字号的方法略作修改。还是使用相对单位,只不过要改一下它们的参照对象。首先,在每个面板的父元素中添加声明 font-size: 1rem
,这样每个面板无论在页面哪个位置,都有一个可预测的字号。
其次,重新定义标题字号,改成 em
单位制而非 rem
,使其相对于新改好的父元素上的 1rem
字号。按代码清单 2.13 更新样式:
代码清单 2.13 创建一个大面板
.panel {
font-size: 1rem; /* 给组件设置一个可预测的字号 */
padding: 1em;
border: 1px solid #999;
border-radius: 0.5em;
}
.panel > h2 {
margin-top: 0;
font-size: 0.8em; /* 用 em 定义其他字号,使其相对于父元素字号 */
font-weight: bold;
text-transform: uppercase;
}
本次修改并不会影响面板的外观,但它可以通过仅新增单个声明来放大面板:用另一个样式值来覆盖父元素上的 1rem
字号即可。由于所有组件的测量值都是基于它的,覆盖后势必影响整个面板的大小。可以通过以下代码定义一个更大的面板:
.panel.large { /* 复合选择器选中同时带 panel 和 large 样式类的元素 */
font-size: 1.2rem;
}
至此,用 class="panel"
将得到一个普通面板;而用 class="panel large"
则将得到一个更大的面板。同理,可以通过设置较小的字号来缩小面板。如果该面板是一个更复杂的组件,并具有多个字号或内边距,只要其内部样式都是用 em
定义的,就仍然可以仅通过一个声明来独立完成缩放。
您无需完全照搬我演示的内容来操作。em
和 rem
的动态特性是一个强有力的工具,可以结合特定需求进行调整。例如,如果不想让圆角半径同步缩放,将其改成 rem
即可,并在希望同步缩放的属性上使用 em
就行了。花时间熟悉这些相对单位,将使您拥有远比纯像素思维更大且更丰富的选择空间。
CSS:一个生机勃勃的活标准
CSS 由大量 W3C 规范定义而成。最初的 CSS 是一个带版本号的单一规范,但在 2.1 版之后,情况发生了变化。
从那以后,CSS 规范分解为独立的模块,每个模块都有各自独立的版本号。背景和边框的规范脱离了盒模型(box model)模块,以及层叠和继承(cascading and inheritance)模块。这样 W3C 就能够制定 CSS 某个细分领域的新版本,而无需更新其他没发生变化的领域。其中部分规范仍然停留在第 3 版(现称第 3 级,即 level 3);但其他规范已经处于第 4 级或更高级别了,如选择器规范(selectors specification);还有一些规范,如弹性盒子(Flexbox)规范,还处于第 1 级。
也就是说,我们将不再使用某个特定版本的 CSS。它是一个不断发展的活标准(living standard)。每个浏览器都在持续增加对新特性的支持;开发人员也在不断使用这些新特性,并适应这些变化。您可能还会听到“CSS3”这个称谓,但严格来讲,它并不是指某个 CSS 规范的 3.0 版本了,而是指 2010 年代初在短期内发布的一系列规范。
CSS 工作组直到最近才决定支持“CSS4”和“CSS5”的定义。它们不会是规范的具体版本,而是成为一个特性功能的集合(assembly):一个由稳定的、业已构成该语言基本组成部分的特性功能(CSS4)、与目前采用率正稳步攀升的新功能特性(CSS5)的集合。本书不会使用这些称谓,因为它们尚未完全定义;但我会介绍这两个类别的功能,甚至一些最终有望被视为部分 CSS6 的全新功能。
em
和 rem
是最常用的相对单位,但它们并不是唯一可用的相对单位类型。在了解了它们提供的灵活性后,下面再来看看另一种重要的相对单位。
(本小节完)