CSS 中的相对单位

2023-05-17 17:05:41 浏览数 (1)

# 相对值的优势

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
代码语言:javascript复制
<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
代码语言:javascript复制
<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 修正。

代码语言:javascript复制
: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>

0 人点赞