页面样式其实大多数情况下都无法速成,需要通过不断地练习、反复地调试才能熟练掌握。但也有一些小伙伴会疑惑为什么写了很久的前端页面,还是写不好页面布局?
其实页面布局有一些很基础的规则,掌握这些规则,很多时候你的疑惑也能迎刃而解。
# 1. 盒模型
盒模型指的是 CSS 基础盒模型。当浏览器对一个文档进行布局的时候,会将每个元素都表示为一个个矩形的盒子,CSS 控制这些盒子的尺寸、属性(颜色、背景、边框等)和位置,渲染引擎则将它们渲染出来。这个模型描述了元素所占空间的内容,每个盒子由四个部分组成:外边框边界(margin
)、边框边界(border
)、内边距边界(padding
)、内容边界(content
),如图:
我们浏览器对文档进行布局的时候,会将每个元素都表示为图中矩形的盒子。我们使用 CSS 样式来控制这些盒子的尺寸、属性(颜色、背景、边框等)和位置,渲染引擎会依据 CSS 规则树和 DOM 节点生成的渲染树进行渲染。
关于盒模型,这里介绍在开发过程中会遇到的常见问题和应用。
(1) 盒模型会发生margin
外边距叠加。当两个或更多个垂直边距相遇时,它们有时被合并(折叠)成单个边距,需要注意的是:
- 外边距(
margin
)的高度大小是各个边距中的最大值 - 行内框、浮动框或绝对定位框之间的外边距不会叠加,相邻的兄弟姐妹、没有内容将父母与后代分开或是空块等三种情况,才会出现外边距叠加
(2) 我们在工作中会常见到一种 CSS3 中新增的盒模型计算方式:box-sizing
属性。盒模型默认的值是content-box
, 新增的值是padding-box
和border-box
。具体的这里不多介绍,大家可以主要关注最常用的border-box
,在border-box
模型下:
- 元素宽高(
width
/height
)等于:content
+padding
+border
- 布局所占宽高等于元素宽高
# 2. 内联元素与块状元素
内联元素和块状元素在页面中的布局效果有很大的不同,通常我们会使用display
来进行调整。
内联元素又称行内元素等,表示位于行内的元素,特点包括:
- 内联元素只能容纳文本或者其他内联元素,只有这些文本或元素可以与其位于同一行
- 内联元素的宽度高度不起作用,因此给内联元素设置宽高是不生效的
- 常见的内联元素:
<a>
/<span>
/<i>
/<strong>
等
块状元素一般是其他元素的容器,可同时容纳内联元素或者其他块状元素,特点包括:
- 块状元素排斥其他元素与其位于同一行
- 块状元素的宽度高度起作用
- 常见的块状元素有:
<div>
/<p>
/<h1>
…<h6>
/<ul>
/<ol>
等
我们可以通过display
属性去设置元素类型,常用的display
属性包括:
block
:块状元素,可以设置宽度width
和高度height
inline
:内联元素,宽度高度不起作用inline-block
:可以理解为块状元素和内联元素的结合- 位于块状元素或者其他内联元素内
- 可容纳其他块状元素或内联元素
- 宽度高度起作用
使用inline-block
可以很方便解决一些问题:使元素居中、给inline
元素(<a>
/<span>
)设置宽高、将多个块状元素放在一行等。
# 3. 元素定位
每一个前端开发都需要认识文档流,关于文档流:正常的文档流也叫普通流,在 HTML 里面为从上到下,从左到右的排版布局。我们常用的布局与position
样式属性紧紧相关,其中position
样式属性包括:
static
(默认值):没有定位,元素出现在正常的流中(忽略top
/bottom
/left
/right
或者z-index
声明)inherit
:规定应该从父元素继承position
属性的值relative
:生成相对定位的元素,相对于其正常位置进行定位,relative
特点包括:relative
元素保持原有文档流,但相对本身的原始位置发生位移,且占空间relative
元素也遵循从上到下,从左到右的排版布局- 相对于其正常位置进行定位,在这里设置了
relative
的元素相对其原本位置(position: static
)进行位移 relative
元素占有原本位置,因此下一个元素会排到该元素后方relative
元素占位不会随着定位的改变而改变,也就是说relative
在文档流中占有的位置与其原本位置(position: static
)相同
absolute
:生成绝对定位的元素,相对于static
定位以外的第一个父元素进行定位。元素的位置通过left
/top
/right
/bottom
属性进行规定。absolute
特点包括:absolute
元素脱离文档流absolute
元素不占位,因此下一个符合普通流的元素会略过absolute
元素排到其上一个元素的后方absolute
元素的定位是相对于static
定位以外的第一个父元素进行定位
fixed
:生成绝对定位的元素,相对于浏览器窗口进行定位。元素的位置通过left
/top
/right
/bottom
属性进行规定。fixed
的特点:fixed
元素脱离文档流fixed
元素不占位fixed
相对于浏览器窗口来定位,不管是否有static
定位以外的父元素absolute
元素会随着页面的滚动而滚动,而fixed
不会
关于position
样式属性在各种场景下的布局效果相对复杂,如果需要熟练掌握还是需要花不少的心思去练习和思考的。
# 4. 元素堆叠
元素的堆叠方式和顺序,除了与position
定位有关,也与z-index
有关,有关z-index
的说明:
- 当同级元素不设置
z-index
或者z-index
相等时,后面的元素会叠在前面的元素上方 - 当同级元素
z-index
不同时,z-index
大的元素会叠在z-index
小的元素上方
除了同级元素以外,z-index
值的设置效果还会受到父元素的z-index
值的影响,它只决定同一父元素中的同级子元素的堆叠顺序,在此之外的场景会比较复杂,大家可以自己去实践下,篇幅关系我们不再这里拓展了。
z-index
样式属性比较常用于多个元素层级控制的时候,比如弹窗一般需要在最上层,就可以通过设置较大的z-index
值来控制。
# 常见页面布局方式
目前来说,前端开发比较常见的布局方式主要有:
- 传统布局方式
- Flex 布局方式
- Grid 布局方式
(1) 传统布局。
传统布局方式基本上借助于上面提到的一些布局规则,结合display
/position
/float
属性以及一些边距、x/y 轴距离等方式来进行布局。
由于文档流、盒模型、等前面都有介绍,这里我们主要补充一下 float 浮动布局方式。给元素的float
属性赋值后,元素会脱离文档流,进行左右浮动,紧贴着父元素的边框或者是上一个同级同浮动元素的边框。
首先了解下float
属性:
float
属性定义元素在哪个方向浮动float
属性可应用于图像,使文本围绕在图像周围float
与block
- 设置
float
浮动的元素自动获取display: block
样式 - 当一个元素浮动之后,不会影响到块级框的布局
- 设置
float
与inline-block
- 当一个元素浮动之后,会影响内联框(通常是文本)的排列和布局
float
浮动若未指明宽度会尽可能地窄,而inline-block
元素会带来空白问题
使用float
属性,必然会遇到一个问题:本属于普通流中的元素浮动之后,包含框内部由于不存在其他普通流元素了,也就表现出高度为 0,又称为高度塌陷。
因此,我们也需要掌握 float 撑开父元素的方法:
- 父元素使用
overflow: hidden
(此时高度为auto
)- 父元素
overflow:hidden
后,首先会计算height: auto
的真实高度,由于其触发了 BFC,需要包含子元素,所以高度不是 0,而是子元素高度(关于 BFC 大家可以自行去了解一下)
- 父元素
- 使父元素也成为浮动
float
元素- 将父容器也改成浮动定位,这样它就可以带着子元素一起浮动了
- 使用
clear
清除浮动- 在浮动元素后方加入
clear: both
的元素,就可以清除浮动撑开父元素 - 其中在样式中添加
clear:right
,理解为不允许右边有浮动元素,由于上一个元素是浮动元素,因此该元素会自动下移一行来满足规则
- 在浮动元素后方加入
通过传统方式布局的优势在于兼容性较好,在一些版本较低的浏览器上也能给到用户较友好的体验。但传统布局需要掌握的知识较多也相对复杂,因此 Flex 布局和 Grid 布局也主要用来解决传统布局的种种不便。
(2) Flex 布局。
Flex 布局基于 Flexible Box 模型,通常被称为 flexbox,是一种一维的布局模型。对于 Flex 布局,我们主要需要掌握几个概念:
- flexbox 的两根轴线:其中,主轴由
flex-direction
定义,交叉轴则垂直于主轴。 - 起始和终止:传统布局的文档流是从左到右、从上到下的布局方式。而在 flexbox 中,我们使用起始和终止来描述布局方向和顺序。
- Flex 容器:采用了 flexbox 的区域(
display
属性值为flex
或者inline-flex
)叫做 flex 容器,容器中的直系子元素就会变为 flex 元素。通过flex-direction
/flex-wrap
/flex
等各种属性设置,我们可以方便地设置容器内元素的布局效果。
使用 Flex 布局可以:
- 通过
flex-direction
调整 Flex 元素的排列方向(主轴的方向) - 用
flex-wrap
实现多行 Flex 容器如何换行 - 使用
justify-content
调整 Flex 元素在主轴上的对齐方式 - 使用
align-items
调整 Flex 元素在交叉轴上如何对齐 - 使用
align-content
调整多根轴线的对齐方式
Flex 布局的出现,解决了很多前端开发居中、排版的一些痛点,尤其是垂直居中,因此现在几乎成为了主流的布局方式。以前我们都是基于盒模型来布局,一般使用display
属性+position
属性+float
属性。Flex 布局给flexbox
的子元素之间提供了强大的空间分布和对齐能力。
除此之外,还可以对 Flex 元素设置排列顺序、放大比例、缩小比例等等。更多的使用方法,大家可以去网上进行相关的查询和学习。
(3) Grid 布局。
Grid 布局又称为网格布局,提供了一种二维布局的方式,它将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系。
我们知道 Flex 布局是基于轴线布局,与之相对,Grid 布局则是将容器划分成行和列,可以像表格一样按行或列来对齐元素。网格容器的子元素可以自己定位,像 CSS 定位的元素一样有重叠和层次关系。
同样的,对于 Grid 布局,我们也需要掌握几个概念:
- 网格轨道与行列:一个网格轨道就是网格中任意两条线之间的空间,可以通过
grid-template-columns
和grid-template-rows
属性来定义网格中的行和列。 - 网格线:当我们定义网格时,我们定义的是网格轨道,Grid 会为我们创建编号的网格线来让我们来定位每一个网格元素。网格线的编号顺序取决于定义的布局方向,水平网格线划分出行,垂直网格线划分出列。
- 网格容器:采用了 Grid 布局的区域(
display
属性值为grid
或者inline-grid
)叫做网格容器,容器中的直系子元素就会变为网格元素。
使用 Grid 布局可以:
- 实现网页的响应式布局
- 实现灵活的 12 列布局(类似于 Bootstrap 的 CSS 布局方式)
- 与其他布局方式结合,与 css 其它部分协同合作
通过 Grid 布局我们能实现任意组合不同布局,其设计可称得上目前最强大的布局方式,它与 Flex 布局是未来的趋势。其中,Grid 布局适用于较大规模的布局,Flex 布局则适合页面中的组件和较小规模布局。
以上这些内容属于比较基础的布局,我们在写 CSS 过程中会遇到很多的神奇现象,而要理解这些现象,就得知道浏览器布局的一些原理逻辑和设定。除了布局以外,很多页面开发也有对 CSS3 动画的一些要求,这里篇幅关系不多介绍,大家可以通过互联网来学习更多的内容。