# 相对值的优势
CSS 为网页带来了后期绑定(late-binding)的样式:直到内容和样式都完成了,二者才会结合起来。这会给设计流程增加复杂性,而这在其他类型的图形设计中是不存在的。不过这也带来了好处,即一个样式表可以作用于成百上千个网页。
当网页打开后,用户还可以缩放网页,CSS 还需要适应新的限制。即不能在刚创建网页时就应用样式,而是等到要将网页渲染到屏幕上时,才能去计算样式。这给 CSS 增加了一个抽象层。我们无法根据理想的条件给元素添加样式,而是要设置无论元素处于任意条件,都能够生效的规则。
CSS 带来的抽象性也带来了额外的复杂性。相对单位就是 CSS 用来解决这种抽象的一种工具。我们可以基于窗口大小来等比例地缩放字号,而不是固定为 14px,或者将网页上的任何元素的大小都相对于基础字号来设置,然后只用改一行代码就能缩放整个网页。
- 常用绝对长度单位
- 像素(px)
- 不常用绝对单位
- 毫米(mm)
- 厘米(cm)
- 英尺(in)
- 点(pt)
- 派卡,印刷术语(pc)
- 换算公式
- 1 in = 25.4 mm = 2.54 cm = 6 pc = 72 pt = 96 px
CSS 像素并不严格等于显示器像素,尤其在高清屏(视网膜屏)下。CSS 单位通常会根据浏览器、操作系统或硬件适当缩放,但是通常 96px 为一个物理英寸的大小。
# em 和 rem
em 是最常见的相对长度单位,适合基于特定的字号进行排版。在 CSS 中,1em 等于当前元素的字号,其准确值取决于作用的元素。
浏览器会根据相对单位的值计算出绝对值,称作计算值(computed value)。
font-size: 12px;
font-size: 18px;
代码语言:javascript复制<html>
<body>
<div class="demo0-container demo0-container-0">font-size: 12px;</div>
<div class="demo0-container demo0-container-1">font-size: 18px;</div>
</body>
</html>
<script>
</script>
<style>
.demo0-container {
padding: 1em;
border-radius: 1em;
background-color: lightgray;
}
.demo0-container-0 {
font-size: 12px;
}
.demo0-container-1 {
font-size: 18px;
}
</style>
# 使用 em 定义字号
如果声明 font-size:1.2em,会发生什么呢?一个字号当然不能等于自己的 1.2 倍。实际上,这个 font-size 是根据继承的字号来计算的。
font-size: 12px;
font-size: 1.2em;
代码语言:javascript复制<html>
<body>
<div class="demo1-container">font-size: 12px;
<p>font-size: 1.2em;</p>
</div>
</body>
</html>
<script>
</script>
<style>
.demo1-container {
font-size: 16px;
}
.demo1-container p {
font-size: 1.2em;
}
</style>
对大多数浏览器来说,默认的字号为 16px。准确地说,medium 关键字的值是 16px。
# em 同时用于字号和其他属性
同时用 em 指定一个元素的字号和其他属性。这时,浏览器必须先计算字号,然后使用这个计算值去算出其余的属性值。这两类属性可以拥有一样的声明值,但是计算值不一样。
font-size: 12px;
font-size: 1.2em;
代码语言:javascript复制<html>
<body>
<div class="demo2-container">font-size: 12px;
<p>font-size: 1.2em;</p>
</div>
</body>
</html>
<script>
</script>
<style>
.demo2-container {
font-size: 16px;
background-color: lightgray;
}
.demo2-container p {
font-size: 1.2em; /* 1.2em => 16px X 1.2 */
background-color: lightgreen;
padding: 1.2em; /* 1.2em => 16px X 1.2 X 1.2 */
}
</style>
# 字体缩小问题
当用 em 来指定多重嵌套的元素的字号时,就会产生意外的结果。为了算出每个元素的准确值,就需要知道继承的字号,如果这个值是在父元素上用 em 定义的,就需要知道父元素的继承值,以此类推,就会沿着 DOM 树一直往上查找。
当列表多级嵌套并且给每一级使用 em 定义字号时,就会发生文字缩小的现象。
- Top Level
- Second Level
- Third Level
- Fourth Level
- Fifth Level
- Fourth Level
- Third Level
- Second Level
<html>
<body>
<div class="demo3-container">
<ul>
<li> Top Level
<ul>
<li> Second Level
<ul>
<li> Third Level
<ul>
<li> Fourth Level
<ul>
<li> Fifth Level</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</body>
</html>
<script>
</script>
<style>
.demo3-container {
font-size: 16px;
}
.demo3-container ul {
font-size: .8em;
}
</style>
# 使用 rem 设置字号
当浏览器解析 HTML 文档时,会在内存里将页面的所有元素表示为 DOM (文档对象模型)。它是一个树结构,其中每个元素都由一个节点表示。<html>
元素是顶级(根)节点。它下面是子节点,<head>
和 <body>
。再下面是逐级嵌套的后代节点。
在文档中,根节点是所有其他元素的祖先节点。根节点有一个伪类选择器(:root)
,可以用来选中它自己。这等价于类型选择器 html,但是 html 的优先级相当于一个类名,而不是一个标签。
rem 是 root em 的缩写。rem 不是相对于当前元素,而是相对于根元素的单位。
- Top Level
- Second Level
- Third Level
- Fourth Level
- Fifth Level
- Fourth Level
- Third Level
- Second Level
<html>
<body>
<div class="demo4-container">
<ul>
<li> Top Level
<ul>
<li> Second Level
<ul>
<li> Third Level
<ul>
<li> Fourth Level
<ul>
<li> Fifth Level</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</body>
</html>
<script>
</script>
<style>
.demo4-container ul {
font-size: 1.2rem;
}
</style>
与 em 相比,rem 降低了复杂性。实际上,rem 结合了 px 和 em 的优点,既保留了相对单位的优势,又简单易用。那是不是应该全用 rem,抛弃其他选择呢?答案是否定的。
无法确定时,用 rem 设置字号,用 px 设置边框,用 em 设置其他大部分属性。
# 停止像素思维
在响应式网页中,需要习惯“模糊”值。1.2em 到底是多少像素并不重要,重点是它比继承的字号要稍微大一点。如果在屏幕上的效果不理想,就调整它的值,反复试验。这种方式同样适用于像素值。
# 设置一个合理的默认字号
如果你希望默认字号为 14px,那么不要将默认字体设置为 10px 然后再覆盖一遍,而应该直接将根元素字号设置为想要的值。将想要的值除以继承值(在这种情况下为浏览器默认值)是 14/16,等于 0.875。
代码语言:javascript复制:root {
font-size: 0.875em; /* 14 / 16 = 0.875 */
}
# 构造响应式面板
可以根据屏幕尺寸,用媒体查询改变根元素的字号。这样就能够基于不同用户的屏幕尺寸,渲染出不同大小的面板。
代码语言:javascript复制:root {
/* 作用到所有的屏幕,但是在大屏上会被覆盖 */
font-size: 0.75em;
}
@media (min-width: 800px) {
/* 仅作用到宽度 800px 及其以上的屏幕,覆盖之前的值 */
:root {
font-size: 0.875em;
}
}
@media (min-width: 1200px) {
/* 仅作用到宽度 1200px 及其以上的屏幕,覆盖之前的两个值 */
:root {
font-size: 1em;
}
}
# 缩放单个组件
需要让同一个组件在页面的某些部分显示不同的大小,你可以用 em 来单独缩放一个组件。
# 视口的相对单位
相对于浏览器视口定义长度的视口的相对单位。
视口——浏览器窗口里网页可见部分的边框区域。它不包括浏览器的地址栏、工具栏、状态栏。
- 视口的相对单位
- vh: 视口高度的 1/100
- vw:视口宽度的 1/100
- vmin:视口宽、高中较小的一方的 1/100(IE9 中叫 vm,而不是 vmin)
- vmax:视口宽、高中较大的一方的 1/100
vmin 取决于宽和高中较小的一方,这可以保证元素在屏幕方向变化时适应屏幕。在横屏时,vmin 取决于高度;在竖屏时,则取决于宽度。
代码语言:javascript复制/* 生成了一个大正方形,不管如何缩放浏览器,它都能在视口中显示。 */
.square {
width: 90vmin;
height: 90vmin;
background-color: #369;
}
# 使用 vw 定义字号
相对视口单位有一个不起眼的用途,就是设置字号,它比用 vh 和 vw 设置元素的宽和高还要实用。这样做的好处在于元素能够在这两种大小之间平滑地过渡,这意味着不会在某个断点突然改变。当视口大小改变时,元素会逐渐过渡。
不过对于过大或者过小屏幕上,可能会有不适,不过可以通过 calc
修正。
:root {
font-size: calc(0.5em 1vw);
}
0.5em 保证了最小字号,1vw 则确保了字体会随着视口缩放。慢慢缩放浏览器,字体会平滑地缩放。
不用媒体查询就实现了大部分的响应式策略。省掉三四个硬编码的断点,网页上的内容也能根据视口流畅地缩放。
# 无单位数值和行高
支持无单位值的属性:
- line-height
- z-index
- font-weight
任何长度单位(如 px、em、rem)都可以用无单位的值 0,因为这些情况下单位不影响计算值,即 0px、0%、0em 均相等。
一个无单位的 0 只能用于长度值和百分比,比如内边距、边框和宽度等,而不能用于角度值,比如度,或者时间相关的值,比如秒。
line-height 属性比较特殊,它的值既可以有单位也可以无单位。通常我们应该使用无单位的数值,因为它们继承的方式不一样。
继承有一个怪异特性:当一个元素的值定义为长度(px、em、rem,等等)时,子元素会继承它的计算值。当使用 em 等单位定义行高时,它们的值是计算值,传递到了任何继承子元素上。如果子元素有不同的字号,并且继承了 line-height 属性,就会造成意想不到的结果,比如文字重叠。
长度——一种用于测量距离的CSS值的正式称谓。它由一个数值和一个单位组成,比如 5px。长度有两种类型:绝对长度和相对长度。百分比类似于长度,但是严格来讲,它不是长度。
使用无单位的数值时,继承的是声明值,即在每个继承子元素上会重新算它的计算值。这样得到的结果几乎总是我们想要的。可以用一个无单位的数值给 body 设置行高,之后就不用修改了,除非有些地方想要不一样的行高。
# 自定义属性(CSS 变量)
可以声明一个变量,为它赋一个值,然后在样式表的其他地方引用这个值。
代码语言:javascript复制/* 定义一个自定义属性 */
:root {
--main-font: Helvetica, Arial, sans-serif;
/*
定义了一个名叫--main-font的变量。
将其值设置为一些常见的sans-serif字体。
变量名前面必须有两个连字符(--),用来跟CSS属性区分。
变量必须在一个声明块内声明,这使用了:root 选择器,因此该变量可以在整个网页使用
*/
}
CSS入门容易,但精通不易。学习CSS并不是学习一两个小技巧,而是要理解这门语言的方方面面,并知道如何将其搭配使用。
代码语言:javascript复制<html>
<body>
<div class="demo5-container">
<p>
CSS入门容易,但精通不易。学习CSS并不是学习一两个小技巧,而是要理解这门语言的方方面面,并知道如何将其搭配使用。
</p>
</div>
</body>
</html>
<script>
</script>
<style>
.demo5-container {
--main-font: Helvetica, Arial, sans-serif;
--brand-color: #369;
}
.demo5-container p {
font-family: var(--main-font);
color: var(--brand-color);
}
</style>
# 动态改变自定义属性
自定义属性的声明能够层叠和继承:可以在多个选择器中定义相同的变量,这个变量在网页的不同地方有不同的值。
深入 CSS
CSS入门容易,但精通不易。学习CSS并不是学习一两个小技巧,而是要理解这门语言的方方面面,并知道如何将其搭配使用。
深入 CSS
CSS入门容易,但精通不易。学习CSS并不是学习一两个小技巧,而是要理解这门语言的方方面面,并知道如何将其搭配使用。
代码语言:javascript复制<html>
<body>
<div class="demo6-container">
<div class="panel">
<p>深入 CSS</p>
<div class="content">CSS入门容易,但精通不易。学习CSS并不是学习一两个小技巧,而是要理解这门语言的方方面面,并知道如何将其搭配使用。</div>
</div>
<aside class="dark">
<div class="panel">
<p>深入 CSS</p>
<div class="content">CSS入门容易,但精通不易。学习CSS并不是学习一两个小技巧,而是要理解这门语言的方方面面,并知道如何将其搭配使用。</div>
</div>
</aside>
</div>
</body>
</html>
<script>
</script>
<style>
.demo6-container {
--main-bg: #fff;
--main-color: #000;
}
.demo6-container .panel {
font-size: 1rem;
padding: 1em;
border: 1px solid #999;
border-radius: 0.5em;
background-color: var(--main-bg);
color: var(--main-color);
}
.demo6-container .panel > p {
margin-top: 0;
font-size: 0.8em;
font-weight: bold;
}
.demo6-container .dark {
margin-top: 2em;
padding: 1em;
background-color: #999;
--main-bg: #333;
--main-color: #fff;
}
</style>