当一行不换行

Avatar of Welling Guzman
Welling Guzman

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 $200 免费积分!

我们期望一行在文本到达父级盒子边界时换行。我们每次创建段落时都会看到这一点,就像这段一样。当父级盒子没有足够的空间容纳下一行中的下一个单词时,它就会换行并移动到下一行,并重复此过程。

好吧,这就是单词之间用空格或其他空白字符分隔时的工作原理。就 CSS 而言,有五个 (!) 属性 可能影响行换行的方式和时机。不过,我们不要再深入讨论这个问题了。相反,让我们看看一个看似要换行但实际上没有换行的场景,以此来学习一些关于行换行的知识。

在一个浏览器无法知道何时可以换行的场景中会发生什么?

让我们用一个“标签列表”把自己陷入困境,然后摆脱困境。这是我们的标记

<ul>
  <li>PHP</li>
  <li>JavaScript</li>
  <li>Rust</li>
  <!-- etc. -->
</ul>

接下来,我们将应用 CSS,将默认的列表样式从默认的垂直方向覆盖到水平方向,方法是将列表项设置为内联显示。

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}


li {
  display: inline;
  padding-right: 5px;
}

列表看起来正是我们想要的。我在一个列表项和另一个列表项之间添加了一点间距,因此看起来不会太拥挤。

现在让我们将一个包装元素引入到混合中。本质上是围绕无序列表的 div。我们可以给它一个类,比如 .tags

<div class="tags">
  <ul>
    <li>PHP</li>
    <li>JavaScript</li>
    <li>Rust</li>
  </ul>
</div>

假设我们想给包装器一个固定的宽度 200px。我们应该期望看到换行发生,因为无序列表会撞到包装器的边界。

.tags {
  width: 200px;
}

有趣的部分来了。许多人在他们的构建过程中使用缩小器来减少文件大小,方法是删除不必要的数值。其中一些数值是空白,包括空格、制表符和换行符(如回车符和换行符)字符,这些字符用于格式化目的,但缩小器认为它们与最终结果无关。

如果我们通过删除新行来“缩小”我们的 HTML,那么我们将得到以下内容

<div class="tags"><ul><li>PHP</li><li>JavaScript</li><li>Rust</li></ul></div>

哦,不。如您所见,列表不再在 200px 边界处换行。为什么?现在有什么不同?我个人认为 HTML 不关心空白。缩小后的版本与原始标记有什么不同?

浏览器确实关心空白……但只有有时。当页面被解析时,解析器将此列表视为一个长单词,因为从它的角度来看,没有字符能将一个单词与另一个单词区分开来。

有人可能会认为填充会影响事情。但如果我们从列表项中删除填充,我们仍然会得到相同的结果……只是项之间没有间距。

浏览器将整个列表视为一个单词。

我们可以从特殊字符获得自然换行

除了空格之外,不包括不换行空格 (&nbsp;),还有一些其他字符会导致强制换行,包括

  • 连字符 (-) 后
  • en 连字符 () 后
  • em 连字符 () 前后
  • 问号 (?) 后
  • 零宽度空格 (U+200B&#8203;)

这些换行发生在渲染时,这意味着浏览器仍然将此视为一个长单词。在标签列表中添加一个带有这些字符的任何一个新列表项将强制换行。让我们在列表中添加“Objective-C”。它的名称包含一个连字符,我们可以用它来查看它如何影响事情。

为了提高可读性,代码将具有缩进和新行。

<div class="tags">
  <ul>
    <li>PHP</li>
    <li>JavaScript</li>
    <li>Rust</li>
    <li>Objective-C</li>
  </ul>
</div>

很好。让我们看看解决我们的非换行列表的三个解决方案。

解决方案 1:添加一个换行符

我们可以继续使用这些换行符来强制换行,就像我们刚刚做的那样。但请记住,如果您使用的是缩小器,在结束标签中或结束标签后添加空格并不能保证它不会被删除,因为并非所有缩小器的工作方式都相同。

<div class="tags">
  <ul>
    <li>PHP </li>
    <li>JavaScript </li>
    <li>Rust </li>
    <li>Objective-C </li>
  </ul>
</div>

解决方案 2:使用伪元素

换行符也可以使用 CSS 中的 ::before::after 伪元素添加。使此解决方案有效的因素是它不受 HTML 缩小器的影响,因为空格是在应用 CSS 时添加的。

但是,在我们继续之前,让我们花点时间谈谈空白字符的折叠。

浏览器会折叠内联元素中强制换行符字符前后出现的空白字符。考虑到这一点,使用 ::after 和具有空格和 display: inline-block 的内容属性有一个小技巧。内联块元素在文本末尾添加了一个换行符。然后,内容属性空格出现在内联块元素创建的换行符之后,这会导致空格在渲染时被删除。也就是说,除非 white-space 属性设置为 pre。

解决方案 3:使用内联块而不是

也许您之前在 CSS 中遇到过内联块元素之间空格的斗争。我们可以对 display 属性使用 inline-block 值来强制换行,因为内联块元素已经有了我们需要的额外空格。这与添加零宽度空格字符类似,但列表项之间将没有视觉分离。

解决方案 4:使用 flex 或 inline-flex

另一种解决方案是将无序列表定义为一个 flex 容器,这允许我们使用 flex-flow 来设置列表的方向,并在需要时确保它可以跨多行。

我们也可以使用 display: inline-flex 而不是 inline-block 解决方案。这里的想法是让整个 flex 容器内联显示。


因此,我们从一个使用缩小器时可能会遇到的情况开始。也就是说,缩小器(以及许多库)非常智能,会尝试阻止此换行问题发生。

当然,这不是一个非常常见的情况。这实际上是那些如果我们不注意就会被忽略的事情之一,但如果它确实发生了,至少我们知道有一些方法可以解决它。