HTML的空白字符何时重要

HTML的空白字符何时重要
守拙原文链接
When does white space matter in HTML?
作为一个网页开发者,你通常不会花太多时间考虑空白字符,对吧?我是说,它们真的有多重要呢?好吧,希望在阅读了这篇文章之后,你会更经常地想到它们,或者至少知道它们何时重要,以及如何追踪它们!
什么是空白字符?
空白字符是指只由空格、制表符或换行符(准确地说,是CRLF序列、回车符或换行符)组成的任何文本字符串。
作为一个编写代码的人,你可能知道这些字符的至关重要性。它们使你能够以一种方式格式化你的代码,使其易于你自己和其他人阅读。事实上,我们的大部分源代码都充满了这些空白字符(除非你编写的是混淆代码)。它们最常用于将代码拆分为多行并缩进行以表示元素的嵌套。
但是,这些字符对于阅读代码的人来说很重要,并不意味着它们对于访问你的网页的人很重要。如果这些仅用于格式化的字符影响了页面的布局,它们看起来可能不会太好,对吧?
让我们来看一个简单的例子:
1 |
|
这段源代码在DOCTYPE后包含一个换行符,在h1标签之前和内部包含很多空格字符,但浏览器似乎根本不在乎,只是显示了“Hello World!”这几个字,就好像这些字符根本不存在一样!
与文字处理应用程序不同,浏览器似乎完全忽略了空白字符(至少大多数时候是这样)。
CSS如何处理空白字符?
如果大部分空白字符都被忽略,那并不是所有的都被忽略。在前面的例子中,页面渲染时“Hello”和“World!”之间的空格仍然存在。所以,浏览器引擎中一定有某种机制来决定哪些空白字符是有用的,哪些不是。
如果你是那种喜欢阅读规范的人,你可能会喜欢CSS Text Module Level 3规范,特别是关于CSS空白字符属性和空白字符处理细节的部分,但如果你是那种人,你现在可能不会读这篇文章。
让我们再来看一个非常简单的例子(为了简单起见,我用◦表示所有空格,⇥表示所有制表符,⏎表示所有换行符):
1 | <h1>◦◦◦Hello⏎ |
这是这个示例标记在浏览器中的渲染方式:
h1元素只包含内联元素。事实上,它包含一个文本节点(由一些空格、单词Hello和一些制表符组成),一个内联元素(span,包含一个空格和单词World!)以及另一个文本节点(仅由制表符和空格组成)。
因此,它建立了所谓的内联格式化上下文。这是浏览器引擎处理的布局渲染上下文之一。
在这个上下文中,空白字符的处理如下(这过于简化了,规范中有更多的细节):
首先,所有在换行符前后的空格和制表符都被忽略,所以如果我们采用之前的例子并应用这条规则,我们得到:
1 | <h1>◦◦◦Hello⏎ |
然后,所有制表符字符被视为空格字符,所以示例变为:
1 | <h1>◦◦◦Hello⏎ |
接下来,换行符被转换为空格:
1 | <h1>◦◦◦Hello◦<span>◦World!</span>◦◦◦</h1> |
然后,任何紧跟在另一个空格后的空格(甚至在两个单独的内联元素之间)都被忽略,所以我们最终得到:
1 | <h1>◦Hello◦<span>World!</span>◦</h1> |
最后,行首和行尾的空格序列被移除,所以我们最终得到这个:
1 | <h1>Hello◦<span>World!</span></h1> |
这就是为什么访问网页的人只会看到页面顶部整齐书写的短语“Hello World!”,而不是一个奇怪缩进的“Hello”,后面跟着一个更奇怪的缩进“World!”在下一行。
访问者将看到左侧的渲染效果,而不是右侧的。
使用Firefox DevTools(从52版本开始,现在支持突出显示文本节点),你可以看到分隔这两个词的空间是包含“Hello”的节点的一部分,就像我们在应用空白字符处理规则后得到的标记一样:
1 | <h1>Hello◦<span>World!</span></h1> |
突出显示单词“Hello”显示h1元素中唯一的剩余空间是这个文本节点的一部分。
现在我们知道了在内联格式化上下文中空白字符是如何被处理的(记住,基本上它是一个只包含内联元素的元素)。
你可能想知道在其他类型的上下文中空白字符是如何被处理的,以及这些上下文到底是什么。
好吧,如果一个元素至少包含一个块级元素,那么它就建立了所谓的块格式化上下文!
在这个上下文中,空白字符的处理方式非常不同。让我们来看这个例子(现场查看:示例3):
1 | <body>⏎ |
我们有3个只包含空白字符的文本节点,一个在第一个div之前,一个在两个div之间,一个在第二个div之后。
浏览器引擎可能以不同的方式优化这一点,但为了理解,我将采用以下解释:
因为我们在块格式化上下文中,一切都必须是块,所以我们的3个文本节点也变成了块,就像两个div一样。
块占据可用的全部宽度并相互堆叠,这意味着我们最终会得到由以下块列表组成的布局:
1 | <block>⏎⇥</block> |
我们可以进一步简化它,通过应用内联格式化上下文中空白字符的处理规则:
1 | <block></block> |
我们现在有的3个空块在最终布局中不会占用任何空间,因为它们什么都不包含,所以我们确实只会在页面上定位2个块。访问网页的人将看到单词“Hello”然后是“World!”在两行上,正如你所期望的两个div的布局。
所以,在这种情况下,浏览器引擎基本上忽略了源代码中添加的所有空白字符。
两个块级元素堆叠在一起,所有空白字符都被忽略。现场查看:示例3。
为什么我们在开发者工具中看不到空白字符?
我们在前一节中看到,渲染布局时经常忽略空白字符,但它们在DOM树中仍然扮演着角色。文本节点仍然在页面的DOM树中被创建,所以如果你自己尝试,你会看到这些文本节点就是不在那里。
文本节点在Firefox中被忽略
并且在Chrome中也被忽略
原因是如果浏览器引擎在创建布局时忽略了这些只包含空白字符的文本节点,那么开发者工具也忽略它们也是安全的。毕竟,作者只为格式化使用它们,访问者看不到它们。所以开发者工具没有必要显示它们。
现在,事实上有些情况下在开发者工具中显示空白字符文本节点可能会很有用。以下部分将描述它们是什么。
内联和内联块元素之间的空格
事实上,我们已经在本文的第一个例子中看到了这一点,当时我们描述了在内联格式化上下文中如何处理空白字符。
我们说有一些规则可以忽略大多数字符,但是某些空格仍然保留,基本上,是为了分隔单词。
所以,当你实际上处理的只是文本,可能包含em、strong、span等内联元素的段落时,你通常不会关心这个,因为到达布局的额外空白空间实际上有助于分隔单词。
但当你开始使用内联块元素时,情况就变得更有趣了。这些元素从外部看起来像内联元素,但在内部表现得像块,所以它们经常被用来显示比同一行上的文本更复杂的UI片段(就像浮动块一样)。
我认为网页开发者的期望是,因为它们是块,它们会表现得像块一样,并且只是并排堆叠(而不是相互堆叠),但实际上它们并不是。如果标记之间有格式化空白字符,那么这将在布局中创建空间,就像文本之间一样。
考虑这个例子:
1 | <style> |
如果你在浏览器中打开这个,你会看到以下结果:
这很可能不是你的意图。假设这是一列表人的头像,你希望它们这样显示:
这是一个非常常见的CSS布局问题,已经有关于这个问题的问题和文章被写过。存在解决方案,比如完全摆脱空白字符,将你的字体大小设置为0,或者使用负边距等。
这里有趣的不是解决这个常见问题的方法,而是这个问题本身很常见,许多网页开发者至少花了一点时间面对它。
突然间,空白字符以你意想不到的方式出现在你的布局中,你可能需要一段时间才能弄清楚问题所在。
因为相应的文本节点不在开发者工具中,如果人们之前没有遇到过这个常见问题,他们会在这个常见问题上浪费时间。他们会检查是否有边距,但找不到。
所以,这是显示开发者工具中空白字符文本节点实际上有用的一个例子。让我们再看一个。
控制空白字符渲染
使用CSS的white-space属性,你可以控制当给定的内联格式化上下文被布局时空白字符是如何被处理的。
css-tricks.com上有一篇关于这个属性的好文章。
重要的是,如果你将这个属性设置为pre、pre-wrap或pre-line,这实际上会尊重源HTML代码中的一些或全部空白字符,并且它们将开始在布局中占据空间。
如果我们采用前面简单的例子:
1 | <h1>◦◦◦Hello◦⏎ |
但添加以下CSS规则:
1 | h1 { white-space: pre; } |
我们最终得到以下布局:
使用Firefox开发者工具突出显示文本节点,你可以看到“Hello”文本节点占用的空间。现场查看:示例5。
如你所见,h1元素内的布局尊重源HTML文件的格式。在单词“Hello”之前有一些空格,然后是一个换行符,然后是更多的空格和单词“World!”。
实际上,正如你所看到的,开发者工具在h1元素中显示的第一个节点是一个文本节点,悬停在它上面确实突出显示了该节点在页面中占用的空间。
悬停在span元素上也会突出显示页面中占用的空间,特别是,你可以看到来自:
1 | <span>◦World!</span> |
因此,这是开发者工具应该显示空白字符文本节点的第二个原因。的确,一个试图理解布局并且不知道white-space属性的人可能会感到困惑。
Firefox开发者工具来拯救!
从Firefox 52版本开始,检查器面板在它们确实影响布局时显示空白字符文本节点,并且在页面中突出显示它们。
检查器怎么知道一个节点是否影响布局?它简单地检查那个空白字符文本节点是否有大小。当一个文本节点被忽略时,它将有0的宽度和高度,但当它参与布局时,它会有一些尺寸。
所以,使用这个简单的启发式方法,Firefox开发者工具可以显示重要的空白字符文本节点。
在检查器中显示空白字符文本节点并在页面中突出显示。现场查看:示例4。
如你所见,页面中确实有大小的空白字符文本节点现在在检查器面板中显示了,如果你悬停在它们上面,它们也会在页面中突出显示,这样你就知道它们在哪里以及它们有多大。
这样,如果你最初对为什么页面中的头像没有并排坐着感到困惑,现在就会非常清楚为什么是这样了。不再浪费时间寻找不存在的边距或制作正确的谷歌搜索查询以获得答案。
事实上,你甚至可以删除这些文本节点,并看到内联块元素现在显示得正如你所愿。
删除空白字符文本节点。现场查看:示例4。
Firefox 52现在可作为夜间构建版本使用,所以去获取它并尝试一下。
希望这个新功能和这篇文章对你有所帮助,感谢阅读!








