【CSS in Depth 2 精译_073】第 12 章 CSS 排版与间距概述 + 12.1 间距设置(中):对 CSS 行高的深入思考

当前内容所在位置(可进入专栏查看其他译好的章节内容)

  • 第四部分 视觉增强技术 ✔️
  • 【第 12 章 CSS 排版与间距】 ✔️
    • 12.1 间距设置
      • 12.1.1 使用 em 还是 px
      • 12.1.2 对行高的深入思考 ✔️
      • 12.1.3 行内元素的间距设置

文章目录

  • [12.1.2 对行高的深入思考 Factoring in line height](#12.1.2 对行高的深入思考 Factoring in line height)

《CSS in Depth》新版封面

译者按

前面章节在提到行高的设置时,作者往往会说"详见第 12 章";本篇就是对 CSS 行高的一次深入探讨。说是深入,其实也仅仅介绍了文字排版中的冰山一角,但对于还原设计稿中的精确尺寸已经足够了。CSS 很多规则看似简单,但认真深究的话很可能惊掉在座各位的下巴,比如文中提到的那个全新的 leading-trim 属性,看看那篇参考文章就知道了。

12.1.2 对行高的深入思考 Factoring in line height

设计稿中的文字周围还设置了一些间距,具体大小如图 12.3 所示(这里可能有点看不清楚,图中的内容栏是一块白色区域,其所在容器的背景则是很浅的浅灰色。文字区域的顶部和左侧到分栏边缘的距离均为 25px)。

【图 12.3 正文板块内部和文字周围需要设置的间距】

文字周围环绕的 25px 间隔,可以考虑为板块添加内边距来实现。为了让该间隔对更大的字体作出响应,以实现同步呼吸的效果来确保良好的可读性,这里的间距选择使用相对单位 em。经计算,25px / 16px = 1.5625em

而标题与正文段落间的 30px 就没那么简单了。如果在二者之间指定 30px 的外边距,那么它们的实际间距会接近 36px。要理解为什么会这样,需要先来看看元素的高度究竟是如何定义的。

在盒模型中,元素的内容盒(content box)被该元素的内边距环绕,再往外则是元素边框,最后是其外边距。但对于这些元素而言,内容盒可不仅仅只有渲染出的文字部分;真正决定内容盒最终高度的,是元素的行高。这个高度覆盖了文字的顶部与底边,如图 12.4 所示。可以看到,当前文字的高度为 1em,而行高略微超出了文字的上下边缘。

【图 12.4 行高定义了内容盒的高度】

示例页上的行高为 1.4,这是从 <body> 元素指定并继承过来的。这样一来,对于只有一行的文本元素,其内容盒的行高就是 1.4em,而文字则基于该行高垂直居中对齐;又因为当前字号为 16px,因此内容盒的最终高度即为 22.4px,多出的 6.4px 则平均分配到文字的上方和下方。

因此,如果为标题设置 30px 的底部外边距,则外边距的顶部与标题文字间实际将多出 3.2px 的间距,并且下方段落的内容盒也会多出来 3.2px(超出的间距是相等的,因为标题和段落具有相同的行高和字号)。这就导致了标题文本和正文段落间的实际间隔为 36.4px

注意

印刷领域的设计师习惯使用 行距(leading 来表示每行文字之间的间距。而在 CSS 中,文字间距是由行高(line height)控制的,不能直接等同为行距。

设计师通常不会在意一两个像素的差异,但多出 6½ 个像素就有点过分了。如果行高比现在还要高,或者元素设置了更大的字号,这样的尺寸偏差还会更加显著。

想要从根本上消除这样的差异,就需要算出多出的检举并在外边距中予以扣除。外边距不能指定为 30px 了,需要扣除 6px,变为 24px;再除以 16px,从而得到相对单位下的 1.5em。根据下列代码清单 12.3 所示内容同步更新本地样式表:

代码清单 12.3 设置内容板块和段落之间的间距

css 复制代码
@layer global {
  p {
    margin-block: 1.5em; /* 为段落添加外边距 */
  }
}

/* ... */

@layer modules {
.tile {
  background-color: var(--white);
  border-radius: 0.3em;
  padding: 1.5625em; /* 在内容板块的内部指定内边距 */
}
.tile > h4 { /* 在内容板块的标题下方设置外边距 */
  margin-block: 0 1.5em;
}

上述代码中,外边距 1.5em 已在全局生效,因此页面中的所有段落都将具有相同的间距。然后在内容板块的标题下方(即 .tile > h4 元素下方)重复该操作,这样即便后面没有段落内容,标题下方的间距都将保持不变。由于存在外边距折叠效应,这两个外边距会相互重叠,从而在标题和段落间产生一个标准的 30px 间距。

说明

CSS 即将推出一个全新的属性 leading-trim,用于消除内容盒上下边缘的多余间距,不过该属性目前尚未获得任何浏览器的官方支持。想了解更多 leading-trim 的相关介绍,可以参考 Ethan Wang 刊登在 Medium 网站的这篇文章《Leading-Trim: The Future of Digital Typesetting 》(https://mng.bz/67PR)。

译注:

截至 2024 年 12 月 10 日 Can I Use 网站最新的统计资料,各浏览器对 leading-trim 属性的支持率仅为 0.09%,目前仅 Safari 浏览器提供了相关支持;不过后续进展非常值得关注。

【补图1:Can I Use 网站公布的各大浏览器对 leading-trim 属性的支持情况(截至 2024 年 12 月 10 日)】

视觉稿还需转换的最后一处间距,位于巨幅主图中的标语附近,如图 12.5 所示:

【图 12.5 设计稿要求在标语上方预留 95px 的间距,而在其下方预留 16px 的间距(即标语和按钮之间)】

标语处的行高同样会影响到这些间距的设置,因为它的字号更大。标语处的字号为 1.95rem,乘以基准字号 16px,即 31.2px;再乘以 1.4 倍的行高,算得的最终行高大小为 43.68px,因此会在文字上下分别多出约 6px 的间距。

既然行高已经在文字上方占据了 6px,因此只需再增加 89px 的间隔就能满足上方间距的要求;同理,标语下方也只需再增加 10px 的间距,就能满足视觉稿中标语下方的间距要求。由于其间涉及大量的算术运算,最简单的解决办法通常是和设计师一起坐下来,在浏览器中实时修改这些间距值,直到获得设计师的首肯。

译注

为方便对照,这里直接给出示例页主图部分的 HTML 片段:

html 复制代码
<div class="hero">
  <div class="hero__inner">
    <h2>Team collaboration done right</h2>
    <a href="/sign-up" class="button button--cta">Get started</a>
  </div>
</div>

明确要在标语上下位置添加的具体间距尺寸后,就可以将其更新到样式表中了。具体样式详见代码清单 12.4。根据给出的内容同步更新本地样式表,变更位置已添加注释说明。此外还在 hero__inner 容器上设置了最小高度(译注:即 min-block-size),以确保能像设计稿那样撑开一大块屏幕空间。

代码清单 12.4 在主图中设置标语和按钮的位置

css 复制代码
.hero {
  background: url(collaboration.jpg) no-repeat;
  background-size: cover;
  margin-bottom: 40px;
}
.hero__inner {
  max-inline-size: 1080px;
  margin-inline: auto;
  min-block-size: 40svh;
  padding-block: 89px; /* 用新计算的间距值替换此前的估值 */
  padding-inline-end: 12.5em;
  text-align: right;
}
.hero h2 {
  margin-block: 0 10px; /* 定义标语和按钮间的间距大小 */
  font-size: 1.95rem;
}

hero__inner 的顶部内边距定义了标语上方所需的间距。尽管设计稿中并没有标注其右侧的内边距尺寸,但上述代码中也进行了相应设置(译注:即 12.5em)。最后将标语元素的顶部外边距设为 0,这样就不用担心在 hero__inner 的内边距上再多出额外的间距了。

译注

在复盘本篇要点时,偶然发现作者提到的那篇介绍 leading-trim 属性的文章没有完整的翻译版,要么是节选的,要么是收费的(有点过分了)。拟计划完成本章所有内容后,再来翻译这篇文章并放到本专栏。敬请关注!



关于《CSS in Depth》(中译本书名《深入解析 CSS》)

第 1 版 第 2 版
读者评分 原版:4.7 (亚马逊);中文版:9.3(豆瓣) 原版:5.0(亚马逊);中文版:暂无,待出版
出版时间 原版:2018 年 3 月 ;中文版:2020 年 4 月 原版:2024 年 7 月;中文版:暂无,待出版
原价 原版:$44.99 ;中文版:¥139.00 原版:$59.99;中文版:暂无,待出版
现价 原版:$36.49 ;中文版:¥52.54 起步 原版:$52.09;中文版:暂无,待出版
原版国内预订 起步价 ¥461.00 起步价 ¥750.00

本专栏为该书第 2 版高分译文专栏,全网首发,精译精校,持续更新,计划今年内完成全书翻译,敬请期待!!!

目前已完结的章节(可进入本专栏查看详情,连载期间完全免费):

  • 第一章 层叠、优先级与继承(已完结)
    • 1.1 层叠
    • 1.2 继承
    • 1.3 特殊值
    • 1.4 简写属性
    • 1.5 CSS 渐进式增强技术
    • 1.6 本章小结
  • 第二章 相对单位(已完结)
    • 2.1 相对单位的威力
    • 2.2 em 与 rem
    • 2.3 告别像素思维
    • 2.4 视口的相对单位
    • 2.5 无单位的数值与行高
    • 2.6 自定义属性
    • 2.7 本章小结
  • 第三章 文档流与盒模型(已完结)
    • 3.1 常规文档流
    • 3.2 盒模型
    • 3.3 元素的高度
    • 3.4 负的外边距
    • 3.5 外边距折叠
    • 3.6 容器内的元素间距问题
    • 3.7 本章小结
  • 第四章 Flexbox 布局(已完结)
    • 4.1 Flexbox 布局原理
    • 4.2 弹性子元素的大小
    • 4.3 弹性布局的方向
    • 4.4 对齐、间距等细节处
    • 4.5 本章小结
  • 第五章 网格布局(已完结)
    • 5.1 构建基础网格
    • 5.2 网格结构剖析 (上)
      • 5.2.1 网格线的编号(下)
      • 5.2.2 网格与 Flexbox 配合(下)
    • 5.3 两种替代语法
      • 5.3.1 命名网格线
      • 5.3.2 命名网格区域
    • 5.4 显式网格与隐式网格(上)
      • 5.4.1 添加变化 (中)
      • 5.4.2 让网格元素填满网格轨道(下)
    • 5.5 子网格(全新增补内容)
    • 5.6 对齐相关的属性
    • 5.7 本章小结
  • 第六章 定位与堆叠上下文(已完结)
    • 6.1 固定定位
      • 6.1.1 创建一个固定定位的模态对话框
      • 6.1.2 在模态对话框打开时防止屏幕滚动
      • 6.1.3 控制定位元素的大小
    • 6.2 绝对定位
      • 6.2.1 关闭按钮的绝对定位
      • 6.2.2 伪元素的定位问题
    • 6.3 相对定位
      • 6.3.1 创建下拉菜单(上)
      • 6.3.2 创建 CSS 三角形(下)
    • 6.4 堆叠上下文与 z-index
      • 6.4.1 理解渲染过程与堆叠顺序(上)
      • 6.4.2 用 z-index 控制堆叠顺序(上)
      • 6.4.3 深入理解堆叠上下文(下)
    • 6.5 粘性定位
    • 6.6 本章小结
  • 第七章 响应式设计(已完结)
    • 7.1 移动端优先设计原则(上篇)
      • 7.1.1 创建移动端菜单(下篇)
      • 7.1.2 给视口添加 meta 标签(下篇)
    • 7.2 媒体查询(上篇)
      • 7.2.1 深入理解媒体查询的类型(上篇)
      • 7.2.2 页面断点的添加(中篇)
      • 7.2.3 响应式列的添加(下篇)
    • 7.3 流式布局
    • 7.4 响应式图片
    • 7.5 本章小结
  • 第八章 层叠图层及其嵌套
    • 8.1 用 layer 图层来操控层叠规则(上篇)
      • 8.1.1 图层的定义(上篇)
      • 8.1.2 图层的顺序与优先级(下篇)
      • 8.1.3 revert-layer 关键字(下篇)
    • 8.2 层叠图层的推荐组织方案
    • 8.3 伪类 :is() 和 :where() 的用法
    • 8.4 CSS 嵌套的使用
      • 8.4.1 嵌套选择器的使用
      • 8.4.2 深入理解嵌套选择器
      • 8.4.3 媒体查询及其他 @规则 的嵌套
    • 8.5 本章小结
  • 第九章 CSS 的模块化与作用域
    • 9.1 模块的定义
      • 9.1.1 模块和全局样式
      • 9.1.2 一个简单的 CSS 模块
      • 9.1.3 模块的变体
      • 9.1.4 多元素模块
    • 9.2 将模块组合为更大的结构
      • 9.2.1 模块中多个职责的拆分
      • 9.2.2 模块的命名
    • 9.3 CSS 的作用域
      • 9.3.1 CSS 作用域的就近原则
      • 9.3.2 划定作用域的边界
      • 9.3.3 CSS 中的隐式作用域
      • 9.3.4 关于 CSS 作用域与层叠图层
    • 9.4 CSS 模式库
    • 9.5 本章小结
  • 第十章 CSS 容器查询
    • 10.1 容器查询的一个简单示例
      • 10.1.1 容器尺寸查询的用法
    • 10.2 深入理解容器
      • 10.2.1 容器的类型
      • 10.2.2 容器的名称
      • 10.2.3 容器与模块化 CSS
    • 10.3 与容器相关的单位
    • 10.4 容器样式查询的用法
      • 10.4.1 将模块与所在容器解耦
      • 10.4.2 减少重复代码
    • 10.5 本章小结
  • 第 11 章 颜色与对比
    • 11.1 通过对比进行交流
      • 11.1.1 模式的建立
      • 11.1.2 还原设计稿
    • 11.2 颜色的定义
      • 11.2.1 色域与色彩空间
      • 11.2.2 CSS 颜色表示法(RGB、Hex、HSL、HWB、LAB/OKLAB、LCH/OKLCH)
    • 11.3 利用 OKLCH 处理颜色(上篇)
      • 11.3.4 从页面其他颜色衍生出新颜色(下篇)
    • 11.4 思考字体颜色的对比效果
    • 11.5 本章小结
  • 附录
    • 附录A:CSS 选择器参考
    • 附录B:CSS 预处理器简介
相关推荐
腾讯TNTWeb前端团队5 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom10 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom10 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom10 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试