网页布局演进史
本文回顾了网页布局方案的演进史,同时也对比了各类布局方案的特点和适用场景。
写在前面
什么是布局?简单的来说,就是指定元素的位置 + 大小。
为什么要学习布局?因为页面元素的排列方式千变万化,单一的 inline 或者 block 属性无法实现复杂的展示效果。
传统盒模型
传统的 CSS 布局方案通常采用 盒模型 来实现,所有的元素都被一个个的盒子包围着。CSS 盒模型由 content、padding(内边距)、border、margin(外边距)四部分组成。
盒子
display
是 CSS 中最重要的用于控制布局的属性。每个元素都有一个默认的 display 值,这与元素的类型有关。对于大多数元素它们的默认值通常是 block
或 inline
。一个 block 元素通常被叫做块级元素。一个 inline 元素通常被叫做行内元素。
下面介绍两种类型盒子:块级盒子(Block box)和内联盒子(Inline box)。
** 块级盒子特点:**
- 盒子会在内联的方向上扩展并占据父容器在该方向上的所有可用空间,在绝大数情况下意味着盒子会和父容器一样宽。
- 每个盒子都会换行。
- width 和 height 属性可以发挥作用。
- 可以使用 margin、padding 控制元素间距。
* 默认情况下,<div>
、<form>
、标题和段落 <p>
都是块级盒子。
** 内联盒子特点:**
- 盒子不会产生换行。
- width 和 height 属性不起作用。
- 垂直方向的 margin 和 padding 都是无效的。
- 水平方向的内边距、外边距以及边框会被应用且会把其他处于 inline 状态的盒子推开。
* 默认情况下,链接的 <a>
元素、 <span>
、 <em>
以及 <strong>
都是内联盒子。
除了 block 和 inline,常用的 display 属性值还有 inline-block、flex、grid 和 none。
一些特殊元素的默认 display 值是
none
,例如script
。display:none
通常被 JavaScript 用来在不删除元素的情况下隐藏或显示元素。它和
visibility
属性不一样。把display
设置成none
元素不会占据它本来应该显示的空间,但是设置成visibility: hidden;
还会占据空间。
另外,在盒子模型中实际 width=padding-left + padding-right + border,而在 css 中设定的 width 只是 content 的大小。为了解决这个问题,让 CSS 中设定的 width 属性成为最终实际显示的盒子宽度,可以使用 box-sizing: border-box 来实现。
位置
为什么需要 position 属性?因为 display 属性只解决了元素大小和元素间隔的问题,并不能够对元素的坐标位置进行精确定义。
常用的 position 属性有:
- static,默认值。没有定位,元素出现在正常的页面流中。
- absolute,绝对定位。相对于 static 定位以外的第一个父元素定位,常配合 left、top、right 和 bottom 使用。
- fixed,绝对定位。常用于需要固定位置的导航栏、状态栏等,随着页面的滚动,元素位置相较于浏览器窗口不会发生变化。
- relative,相对定位。相对于其正常位置定位。
- inherit,继承父元素的 position 属性值。
浮动
最初,引入
float
属性是为了能让 web 开发人员实现简单的布局,包括在一列文本中浮动的图像,文字环绕在它的左边或右边。你可能在报纸版面上看到过。
上面这段话节选自 MDN 文档中对于 float 属性的描述,清楚地说明了 float 属性的由来。float 属性设计的初衷就是让文本环绕在 float 元素的周围。float 元素可以是图片也可以是文字,甚至是整个 < div > 块。当需要让元素之间环绕排列时,就可以考虑设置 float 属性。
弹性盒模型
弹性盒模型在 CSS3 中被引入,旨在以更加简便和高效的形式实现响应式页面布局。弹性盒模型是一种更加现代的布局模型,在没有特殊需求的情况下,推荐使用 flexbox 而不是传统盒模型。flex 是一种一维的布局模型,单次只能处理一行或一列的内容。与之对应的有二维布局模型 Grid,可以同时处理行和列方向的布局。
轴线方向
flexbox 有两根轴线,分别是主轴和交叉轴。主轴方向由 flex-direction 定义,交叉轴垂直于主轴。在 flexbox 中,元素是沿着主轴方向排列的。
flex-direction 的四个取值(从左至右的书写模式,如英文):
- row,默认值,从左到右。
- row-reverse,从右到左。
- column,从上到下。
- column-reverse,从下到上。
另外一个需要理解的重点是 flexbox 不会对文档的书写模式提供假设。过去,CSS 的书写模式主要被认为是水平的,从左到右的。现代的布局方式涵盖了书写模式的范围,所以我们不再假设一行文字是从文档的左上角开始向右书写,新的行也不是必须出现在另一行的下面。
如果
flex-direction
是row
,并且我是在书写英文,那么主轴的起始线是左边,终止线是右边。如果我在书写阿拉伯文,那么主轴的起始线是右边,终止线是左边。
当在元素无法在 flexbox 的主轴方向完成排列时,就需要考虑如何换行的问题,flex-wrap 属性指定了处理换行的策略。
换行方式
flex-wrap 由三个取值:
- nowrap,默认,不换行。flexbox 中的元素会缩小宽度以适应盒模型。
- wrap,换行,元素会保留原始宽度,当一行排列不下时,会自动换行排列,第一行在上方。
- wrap-reverse,换行,第一行在下方。
简写
flex-direction 属性和 flex-wrap 属性可以被简写在 flex-flow 属性中,格式为 flex-flow: <flex-direction> || <flex-wrap>
。默认情况下 flex-flow: row nowrap
。
对齐方式
justify-content 属性定义了元素 < u>** 在主轴上的对齐方式 **。
- flex-start,左对齐。
- flex-end,右对齐。
- center,居中。
- space-between,两端对齐,项目之间的间隔都相等。
- space-around,每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
align-items 属性定义了元素 < u>** 在交叉轴上的对齐方式 **。
- flex-start:交叉轴的起点对齐。
- flex-end:交叉轴的终点对齐。
- center:交叉轴的中点对齐。
- baseline: 项目的第一行文字的基线对齐。
- stretch(默认值):如果项目未设置高度或设为 auto,将占满整个容器的高度。
align-content 属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
* 主轴方向不能设置 stretch 属性,想想为什么?
排列顺序
在 flexbox 中,元素的排列顺序可以被手动指定。只需要在 order 属性中,输入数值即可。数值越小排列越靠前,默认为 0。
flex 元素上的属性
** 填充比例 **
当主轴方向有剩余空间时,可以通过设置元素的 flex-grow 属性来指定如何放大元素以填充空间。flex-grow 的默认值为 0。
如果所有项目的 flex-grow 属性都为 1,则它们将等分剩余空间(如果有的话)。如果一个项目的 flex-grow 属性为 2,其他项目都为 1,则前者占据的剩余空间将比其他项多一倍。
** 缩小比例 **
flex-shrink 属性定义了项目的缩小比例,默认为 1。
即如果空间不足,该元素将缩小。如果所有项目的 flex-shrink 属性都为 1,当空间不足时,都将等比例缩小。如果一个项目的 flex-shrink 属性为 0,其他项目都为 1,则空间不足时,前者不缩小。
** 元素空间大小 **
在 flexbox 中,元素除了自身会占据 width 大小的空间,还可以设置 flex-basis 属性指定额外的富于空间。在默认情况下,flex-basis 大小即为元素的 width。
**flex 属性 **
flex 属性是 flex-grow,flex-shrink,flex-basis 的简写,默认值为 0 1 auto。至少需要指定 flex-grow 的值,后两个属性可以不被指定。
flex 有两个快捷值:
- auto => 1 1 auto,等比列放大缩小。
- none => 0 0 auto, 不放大也不缩小。
** 独立对齐 **
align-self 属性允许单个元素有和其他元素不一样的对齐方式,默认值为 auto,表示继承父元素的 align-items 属性。
响应式布局
当用户访问网站时,可能使用的是 PC,也可能是移动设备如 iPhone、iPad 等,而这些设备的屏幕分辨率却有着较大的差异。一个优秀的网站,应该能在不同尺寸、分辨率的设备下有着同样优异的阅读和使用体验。在 CSS 中,媒体查询功能为响应式设计提供了可能。
响应式布局的优势显而易见,但是它也带来了一些缺点。例如,在响应式设计的网页中,通常会有着更大的样式表和更复杂的 JavaScript 代码,可能会对网站的性能造成影响。
何时应该采用响应式设计?当桌面端和移动端展示的内容相似,那么响应式设计就是一个非常好的选择。这种应用场景通常出现在文档、博客和产品宣传页面上。实际上,你现在所访问的博客就正是一个响应式设计的网页。
为了方便开发者更好的开发响应式布局的网页,流行的前端 UI 框架如 Bootstrap、Ant Design 和 ElementUI 等采用栅格模型来完成页面的布局工作。在参考资料中给出了对应的链接,感兴趣的朋友可以查看。
参考资料
学习 CSS 布局 ➡ 布局入门推荐
盒模型 - Web 开发者指南 | MDN ➡ 理解传统盒模型
Flex 布局教程 - 阮一峰 ➡ 理解弹性盒模型
[响应式 Web 设计 - Web 开发 | MDN](https://developer.mozilla.org/zh-CN/docs/Web_Development/ 响应式_Web_设计) ➡ 深入了解响应式设计
Bootstrap 4 栅格系统 ➡ 了解栅格系统