【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 预处理器简介
相关推荐
深海的鲸同学 luvi15 分钟前
高德地图离线加载解决方案(内网部署)+本地地图瓦片加载
前端·javascript·html5
码字哥1 小时前
EasyExcel设置表头上面的那种大标题(前端传递来的大标题)
java·服务器·前端
GIS好难学3 小时前
《Vue进阶教程》第六课:computed()函数详解(上)
前端·javascript·vue.js
nyf_unknown3 小时前
(css)element中el-select下拉框整体样式修改
前端·css
m0_548514773 小时前
前端打印功能(vue +springboot)
前端·vue.js·spring boot
执键行天涯3 小时前
element-plus中的resetFields()方法
前端·javascript·vue.js
Days20503 小时前
uniapp小程序增加加载功能
开发语言·前端·javascript
喵喵酱仔__3 小时前
vue 给div增加title属性
前端·javascript·vue.js
dazhong20123 小时前
HTML前端开发-- Iconfont 矢量图库使用简介
前端·html·svg·矢量图·iconfont
m0_748248774 小时前
前端vue使用onlyoffice控件实现word在线编辑、预览(仅列出前端部分需要做的工作,不包含后端部分)
前端·vue.js·word