html/css 的布局规则:
想了解 html/css 的布局规则,重要的不是规则是什么,而是什么因素会影响你使用对应的规则。当你理解了这些因素,那么相同场景下,你自然而然会想到使用什么规则。
场景(场景和关联)
举个例子:
- 土地:大小,价格,建什么东西
一句话概括就是:往容器放东西,怎么放。
土地:容器
大小和价格: 因素
东西:元素
怎么放:规则
那么,应用到浏览器中:
容器:也就是我们的浏览器视口(viewport)
因素:矩形、坐标系、边界
元素:盒模型
规则:文档流、定位、浮动、BFC、flex 等等
前面提到,要了解布局规则,重要的不是规则是什么,而是什么因素会影响你使用对应的规则,那么我们分别介绍下容器、因素、元素、规则,并从中建立关联。
容器(viewport):
web 浏览器视口指的是我们可见的区域,不包括浏览器菜单。移动设备的视口默认值为 980px,一般情况下这比移动设备要大,那么内容就会显示不完全,如果直接缩放那会导致字体变小。为了让视口的值等于移动设备的宽度,我们会在 html 的头部添加以下标签:
1
| <meta name="viewport" content="width=device-width" />
|
因素:
- 矩形:可缩放 -> 响应式布局
- 坐标系:拖拽、视差 -> 定位、滚动条、层叠上下文元素
- 边界:视口有边界、坐标系无边界
可见,容器的不同因素直接影响着我们在实现某种效果时使用哪些规则。接下来看看元素。
元素:
- 标准盒模型:块模型、行内模型
- 怪异盒模型
- 弹性盒模型
先了解下盒模型的结构,从里到外:content → padding → border → margin,各个部分组合在一起就是我们页面上看到的内容

标准盒模型:
我们常说的盒模型指的是 W3C 标准盒模型
- 元素的
width
、height
只包含 content 区域
- 盒子实际大小等于
width
+padding
+border
盒子的实际宽度我们可以看做是总宽度,和元素本身设置的 width 不是一个概念

我们布局中广泛应用的模型,分为块模型和行内模型,我们叫做块元素和行内元素。
块元素
display: block
可以将元素设置为块元素,它拥有以下行为:
- 它占据父元素的所有宽度,绝大数情况下(不包含行内块元素)
- 独占一行
- 拥有
width
和height
属性
- 它的
margin
、border
、padding
属性会将盒子周边的元素给“推开”
行内元素
display: inline
可以将元素设置为行内元素,也叫行内元素,它拥有以下行为:
- 盒子不会独占一行
width
和 height
属性不起作用
- 水平方向的外边距、内边距、边框会被应用,且会把其它
inline
状态的盒子推开
- 垂直方向的外边距、内边距、边框会被应用,但不会把其它
inline
状态的盒子推开
默认为行内元素有:a、span、em、strong
除了标准盒模型,还有怪异盒模型,也可以称 IE 盒模型。因为 IE8 之前,IE 默认使用怪异盒模型,并且没有可用的机制来切换。
怪异盒模型
- 元素的
width
、height
不仅包括content
,还包括padding
和border
- 盒子实际的大小取决于 width

图中我们给盒子设置了width: 200px
,padding: 10px
,那么 content 就会被挤压为 180px(200 - padding * 2)。
应用:使用怪异盒模型能解决 1px 边框线问题。
box-sizing
box-sizing
属性可以切换盒模型模式,默认值是content-box
,可选择有border-box
、inherit
content-box
:w3c 标准盒模型
border-box
:IE 盒模型
inherit
:从父元素集成 box-sizing
属性的值
弹性盒模型
对于一些特殊布局,如水平垂直居中,采用传统布局不容易实现,采用弹性盒模型就很方便实现。
推荐阮一峰老师的文章:Flex 布局教程,再补充容易忽视的几点:
作用在 flex 容器上
display: flex:
默认: align-items: stretch、flex-direction: row
align-content:
指定如何在纵轴上 项目之间和周围 分配空间。单轴下(flex-wrap: nowrap)此属性不生效
align-items:
初始值:stretch
stretch:表示 flex 项目会被拉伸至最高的项目高度的高度
flex-flow: row wrap === flex-direction: row + flex-wrap: wrap
作用在 flex 项目上
flex-grow:
初始值:0
flex-shrink:
初始值:1
flex-basic:
初始值:auto,即项目本身的大小
指定了 flex 项目在主轴上的初始大小(如果主轴是水平轴,那就是 flex 项目的宽,否则是高)
flex: 1 200px === flex: 1 + flex-basic: 200px
指定了 flex 项目在主轴上初始化(width: 200px)后,按比例分配剩余空间
flex 缩写
flex === flex-grow flex-shrink flex-basic
flex: 1
flex: 1,此属性可以按同等比例分配项目的大小,那么它的完整写法是什么呢?
不等于 1 1 auto
重点理解下缩写下 flex-basic 的作用:
在按比例分配项目之前,计算项目是否有多余的空间,默认为 auto,即项目自身的大小。
如果设置为 auto,那么按照项目自身大小初始化后等比例分配剩余空间,也就会出现项目大小不一样的情况,所以不是 1 1 auto。
等于 1 1 带单位的长度值
假设我们设置为 1 1 0px,按照 0px 初始化后等比例分配剩余空间,那每个项目的大小就会相同。
flex 常用布局
需求:同一行内,如果有一个标题占两行,整行标题都占两行,否则默认一行。标题超出两行时用省略号表示,效果如下:

这个需求的难点在于卡片的高度不是固定的。有什么办法可以让同行内的标题高度保持统一?
先看一个两行超出隐藏的实现
1 2 3 4 5 6 7 8 9 10 11 12 13
| .title { width: 200px; background-color: yellow;
word-break: break-all; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } .title2 { background-color: pink; }
|
1 2 3 4
| <div class="title"> 翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁翁 </div> <div class="title title2">请请请请请请请请请</div>
|

先来重点理解display: flex
和 flex 下的height: 100%
- 当我们给容器设置 display: flex 时,那么 align-items 属性的值为 stretch,即同一行内的 flex 项目会被拉伸至最高的项目高度的高度
- 给 flex 项目设置 height: 100%,会填充容器剩余高度。
实现:
- 把容器设置为弹性盒子
display: flex
- 给标题设置
height: 100%
- 给标题兄弟元素设置
flex-shrink: 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <div class="section"> <div class="card"> <div class="card-content">1</div> <div class="card-title"> 请问请问群翁群翁群翁群问请问群翁群翁群翁群问请问群翁群翁群翁群 </div> </div> <div class="card"> <div class="card-content">2</div> <div class="card-title">2222222222</div> </div> <div class="card"> <div class="card-content">3</div> <div class="card-title">3333</div> </div> <div class="card"> <div class="card-content">4</div> <div class="card-title">444</div> </div> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| .section { display: flex; // 同一行内的flex项目会被拉伸至最高的项目高度的高度 flex-wrap: wrap; width: 300px; } .section .card { flex: 1; display: flex; flex-direction: column; border: 1px solid red; margin: 0 10px; } .section .card .card-content { flex-shrink: 0; // 防止被标题height: 100%属性挤压
width: 100px; height: 100px; background-color: pink; } .section .card .card-title { height: 100%; // 填充容器剩余高度
line-height: 20px; // 加上行高样式更稳定 word-break: break-all; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; background-color: yellow; }
|
规则
下面介绍文档流、定位、浮动、BFC 等布局规则。
文档流:
在不对页面元素进行任何控制的情况下,浏览器默认的布局方式。从上到下,从左到右。
定位(position):
解决某个元素随页面发生变化而固定位置,它不作为一种主要布局方式,而是用于管理和微调页面中一些特殊项的位置
- 静态定位:默认值,不做任何
- 相对定位:相对自己定位,不会脱离文档流
- 绝对定位:相对于 html,会脱离文档流,或相对于最近被定位的祖先元素定位。多配个相对定位使用
- 固定定位:相对于浏览器视口固定定位
- 粘性定位:初始像静态定位,当它的位置相对视口达到预设值时,就会想固定定位一样被固定住
浮动(float)
在传统布局里,信息是纵向排列(从上到下)的,浮动可使信息横向排列。浮动会脱离文档流,正常文档流的元素会围绕着浮动元素。
- left:左浮
- right:右浮
- none:不浮动
- inherit:继承父元素浮动属性
在使用浮动时,我们得清楚的知道我们要把元素摆放在哪个位置。因为使用浮动时,可能会存在可视化布局与源顺序不同。
假设现源顺序布局为如下
我们给 div2 和 div3 同时设置 float: right
,那么视觉效果就为:
这是因为 div2 在源顺序上比 div3 等级更高(在 DOM 上,div2 先出现,并声明了 float: right
),所以在视觉上更靠右。
BFC:块级格式化上下文(block format context )
定义:可以看作是一块独立的区域空间,拥有普通盒子没有的一些特性。它解决个体之间的位置交互问题。
触发 BFC 的方法:
- html 根元素
- position: absolute、fixed
- display: flex、inline-block、table-cell
- overflow: 除 visibility
- float: 除 none
来看下元素间的交互问题以及解决方法:
- 同一块 BFC 下,相邻垂直方向盒子外边距会发生重叠:
1 2 3 4
| <div class="box"> <div class="child"></div> <div class="child"></div> </div>
|
1 2 3 4 5 6 7 8 9 10
| .box { width: 150px; border: 1px solid red; } .child { height: 50px; width: 50px; background-color: blueviolet; margin: 50px; }
|

我们给每个 child 设置了margin: 50px
,但它们的间距不是 100px,而是 50px,如果我们想让间距变成 100px,那么只要给其中一个盒子设置为 BFC,这样就不再同一块 BFC 下
1 2 3 4 5 6
| <div class="box"> <div class="wrap"> <div class="child"></div> </div> <div class="child"></div> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| .box { width: 150px; border: 1px solid red; } .child { height: 50px; width: 50px; background-color: blueviolet; margin: 50px; } .wrap { overflow: hidden; }
|

1 2 3
| <div style="border: 1px solid #000;"> <div style="width: 100px;height: 100px;background: #eee;float: left;"></div> </div>
|

为外层 div 添加overflow: hidden
1 2 3
| <div style="border: 1px solid #000;overflow: hidden;"> <div style="width: 100px;height: 100px;background: #eee;float: left;"></div> </div>
|

1 2 3 4 5 6 7 8 9
| <div style="height: 400px;"> <div style="height: 100px;width: 100px;float: left;background: lightblue"> 我是一个左浮动的元素 </div> <div style="width: 200px; height: 200px;background: #eee;"> 我是一个没有设置浮动, 也没有触发 BFC 元素, width: 200px; height:200px; background: #eee; </div> </div>
|

给被浮动元素覆盖的元素添加overflow: hidden
1 2 3 4 5 6 7 8 9
| <div style="height: 400px;"> <div style="height: 100px;width: 100px;float: left;background: lightblue"> 我是一个左浮动的元素 </div> <div style="width: 200px; height: 200px;background: #eee;overflow: hidden;"> 我是一个没有设置浮动, 也没有触发 BFC 元素, width: 200px; height:200px; background: #eee; </div> </div>
|

小结:
解决塌陷:给其中一个盒子设置为 BFC,这样就不再同一块 BFC 下
清除浮动:给浮动元素父元素设置为 BFC
防止元素被浮动元素覆盖:给元素设置 BFC,就不会被浮动元素覆盖
IFC:行内格式化上下文(inline formatting context)

让块水平居中
1 2 3 4 5 6 7 8 9 10 11 12
| .p { width: 100px; background-color: pink;
text-align: center; } .child { width: 50px; background-color: yellow;
display: inline-block; }
|
1 2 3
| <div class="p"> <div class="child">12</div> </div>
|

总结(对 html/css 规则)
抽象点来说,容器就是一个可以容纳个体的空间,当我们把一个个个体放到容器时,容器的因素决定了我们使用什么规则来存放从而更加合理。
具体点来说,视口就是我们的容器,元素就是个体,视口的因素(矩形、坐标系和边界等)决定了我们使用什么规则来布局。元素分为标准盒模型、IE 盒模型和弹性盒模型,规则分为文档流、定位、浮动、BFC 等等。
参考:
https://zhuanlan.zhihu.com/p/183050328
https://blog.csdn.net/weixin_41682025/article/details/110343448