CSS 布局:常规流布局

423 阅读7分钟

前言

自接触前端以来,我一直在使用 CSS。在日常工作中,我所掌握的 CSS 知识已经可以满足大部分工作需求,而且就算遇到一些棘手的布局问题,稍微通过谷歌搜索一下也是能得到解决。但是这些 CSS 的问题就像手指上的肉刺一样,平时可以忽略它的存在,但若不慎被衣服上的毛料给勾到,那感觉还是让人难以遗忘的。

深究起背后的原因,终究是我理解 CSS 的角度不对。这是当我在开始研究 CSS 布局的时候,突然有了一种新的视角来重新看待 CSS。CSS 中各式各样的属性是与其所在的布局共同作用下才呈现出当前页面。布局是指界面内排列和定位视觉元素的模式,不同的布局在确定图形表示的整体结构和组织方面发挥着不同的作用。如果简单认为熟记 CSS 中的各种属性就算熟悉 CSS 的话,无疑陷入与我一样的困境。

现代 CSS 拥有七种布局,其中常规流布局(normal flow)、弹性盒布局(flex)和网格布局(grid)这三种布局的使用最多。所以我准备写大概三篇文章来介绍(挖了个坑🥲),这篇文章主要介绍 CSS 布局的特点,然后会从我所理解的角度讲解下 CSS 属性与布局是如何相爱相杀的。

常规流布局

在 1996 年 CSS1 诞生时,当时的网站上展示主要的内容就是图片和文字。所以 CSS 诞生之初就是为图文信息展示服务的,其设计初衷在于构建易读、合理的文档。常规流布局就是在 CSS 中的一套用来实现强大的图文排版的模式,这种类型的布局适合文字较多的页面,因为它允许用户以线性方式阅读文本。

常规流布局是浏览器默认的 HTML 布局方式,如果你没有在 CSS 中添加声明来明确要求 CSS 使用不同的算法,将会使用常规流布局。

常规流布局在一些中文文章里也被称为“文档流/流”,像什么“脱离文档流”之类的术语其实就是指该元素没有使用默认布局了。

下面这个完全没有 CSS 样式的 HTML 文档,浏览器还能将内容以可读的方式呈现。

可以看到,HTML 完全按照源码中出现的先后次序显示——第一个段落、无序列表、第二个段落。这是 HTML 在常规流布局中的布局行为,因为是在浏览器默认布局中的行为,所以也可以视为元素在默认情况下的布局。

HTML 中有如此多的元素,常见的有 <div><p>、以及 <span><img> 等,这些元素如何在常规流的影响下进行定位与排列?

块级元素和内联元素

默认情况下,元素的内容(content)被放置在一个独立的盒子中。然后在这个盒子的周边会添加内边距(padding)、边框(border)和外边距(margin),形成所谓的盒子模型。元素的内容和样式都是通过这个盒子模型来进行布局的。

box-model.png

一般来说,在常规文档流中的 HTML 元素被分为块级元素内联元素

  • <p><h1><img>等元素被视为块级元素。每个块级元素不会彼此并排放置,它们会试图占据尽可能多的水平空间,同时尽量减少占据的垂直空间。所以每个块级元素会在上一个元素下面另起一行,它们的垂直距离会以指定的外边距(margin)分隔(相邻两个块级元素之间的垂直间距会遵循 外边距折叠原则被折叠)。而且除非被其他 CSS 代码更改,否则块级元素的大小将扩展到内联尺寸的大小。
  • 诸如 <span><strong> 之类的元素被称为内联元素。行内元素的行为就像句子中的单词,一个挨着一个,不会独占一行,只有当没有足够的水平空间时,元素中溢出的内容将下移到新的一行。而且行内元素的宽度随元素的内容变化,无法在行内元素上设置明确的宽度和高度。

块级元素和行内元素的差别可以看下面这个例子。

属性与布局

相信大家都有用过 z-index,这是控制元素层叠顺序的 CSS 属性,z-index 较大的重叠元素会覆盖较小的元素。但是如果你把它用在常规流布局中的元素上,你会发现它不起作用。如果按照我以前的思考方式会认为是我没有给该元素的 position 属性设为 relativeabsolute 之类的值,所以 z-index 不起作用。

我觉得这种思考方式是我一直以来对 CSS 理解上的一些微妙误解,虽然上面层叠问题的解决方案从表象上看是把 positionz-index 组合在一起。但是在这种心智模型下,我遇到问题的解决方法通常是尝试添加组合不同的 CSS 属性以达成效果,所以学习和精进 CSS 变成了掌握更多的 CSS 属性。

但是从常规流布局的设计角度来说,这是可以理解的,因为如果 z-index 可以生效的话,我们会看到文字堆叠在一起的文档,这种情况文档根本没有可读性!回到 z-index 这个例子,如果实在想让 z-index 生效,只需使用其它的布局模式即可。

再看看下面这个经典的 CSS 问题(img 下方出现不明空隙!!)

如果你去网上搜索一下这个问题,大家都会告诉你因为 <img> 是行内元素,而行内元素默认的垂直对齐方式是 baseline 对齐,这意味着图像的底部将与文本所在的不可见水平线对齐,所以图像下方有一些空间。

而从常规流布局的设计角度来看这个现象的话,因为图像是行内元素,所以相当于是段落中的字符。而浏览器在段落中为了确保行内元素不会对周围文本的易读性产生负面影响,默认对行内元素添加了一些额外的垂直空间。

在理解了这种模式以及背后原因后,脑海中自然会浮现出几种解决方法。

  1. <img> 改为块级元素(display: block;
  2. 改变 <img> 的对齐方式(vertical-align: top;
  3. 父元素的行距修改为 0(line-height: 0;

总结

常规流布局作为 CSS 最初的布局模式,其设计初衷是为了构建易读的文档内容展示。通过将元素分为块级和内联两种类型,并运用外边距折叠、基线对齐等机制,常规流布局可以有效地呈现文字和图像等内容。

虽然随着时代发展,新的布局方案如 flexboxgrid 相继出现,但常规流布局作为布局的基石,其精髓和理念仍然值得我们学习和掌握。只有真正理解了常规流布局的工作原理,我们才能更好地运用 CSS 属性,解决实际布局问题。同时,熟悉常规流的设计思路,也有助于我们从更高的层次上把握新兴布局模式。