更新记录
- 2023-09-18:对于“两栏和三栏布局”作了补充。
浮动布局
详见CSS中的浮动与定位 | QT-7274 (qblog.top)
定位布局
详见CSS中的浮动与定位 | QT-7274 (qblog.top)
Flex布局
详见CSS中的盒子模型 | QT-7274 (qblog.top)
Grid布局
网格布局(Grid)是最强大的CSS布局方案,对于早期的浏览器版本兼容性不是很好,但是截止2023年,大部分浏览器已经支持Grid布局:
基本概念
容器属性
grid-template-*
你想要多少行或者列,就填写相应属性值的个数,不填写,自动分配。
grid-template-*
相关
repeat(),第一个参数是重复的次数,第二个参数是所要重复的值。
grid-template-columns: 100px 100px 100px; grid-template-columns: repeat(3, 100px);
auto-fill,有时,单元格的大小是固定的,但是容器的大小不固定,这个属性就会自动填充。
grid-template-columns: repeat(auto-fill, 100px);
fr,为了方便表示比例关系,网格布局提供了fr关键字(fraction的缩写,意为“片段”)。
grid-template-columns: repeat(4, 1fr);
minmax(),函数产生一个长度范围,表示长度就在这个范围之中,它接受两个参数,分别为最小值和最大值。
grid-template-columns: 1fr minmax(150px, 1fr);
auto,表示由浏览器自己决定长度。
grid-template-columns: 100px auto 100px;
网格线,可以用方括号定义网格线名称,方便以后的引用。
grid-template-columns: [c1] 100px [c2] 100px [c3] 100px [c4];
row-gap
/column-gap
一句话解释就是, item(项目)相互之间的距离
row-gap
:行间距
column-gap
:列间距
gap
:行间距+列间距
grid-template-areas
一个区域由单个或多个单元格组成,由你决定 (具体使用,需要在项目属性里面设置)
grid-template-areas
:
- 区域不需要利用,则使用"点"(.)表示。
- 区域的命名会影响到网格线。每个区域的起始网格线,会自动命名为区域名-start,终止网格线自动命名为区域名-end。
grid-auto-flow
划分网格以后,容器的子元素会按照顺序,自动放置在每一个网格。默认的放置顺序是“先行后列”, 即先填满第一行,再开始放入第二行 (就是子元素的排放顺序)
grid-auto-flow
相关
即dense
表示尽可能地填充空隙,以达到更好的利用空间的效果。
justify-items
(水平方向) / align-items
(垂直方向)
设置单元格内容的水平和垂直的对齐方式
justify-items: start | end | center | stretch;
justify-items: start;
justify-items: end;
justify-items: center;
justify-items: stretch;
同理
align-items
。
place-items
属性是align-items
属性和justify-items
属性的合并简写形式。
place-items: <align-items> <justify-items>
;
justify-content
(水平方向) / align-content
(垂直方向)
设置整个内容区域的水平和垂直的对齐方式
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
align-content: start | end | center | stretch | space-around | space-between | space-evenly;
justify-content: center;
justify-content: space-around;
align-content: center;
align-content: space-around;
grid-auto-columns / grid-auto-rows
用来设置多出来的项目宽和高
项目属性
grid-column-start
/ grid-column-end
/ grid-row-start
/ grid-row-end
一句话解释,用来指定item的具体位置, 根据在哪根网格线
从当前列开始,跨越2个网格列,网格项目将占据当前列及其后续的一列,总共跨越两列:
grid-column
/ grid-row
grid-column
属性是grid-column-start
和grid-column-end
的合并简写形式, grid-row
属性是grid-rowstart
属性和grid-row-end
的合并简写形式
grid-area
指定项目放在哪一个区域
grid-area
属性还可用作grid-row-start
、 grid-column-start
、 grid-row-end
、 grid-column-end
的合并
简写形式,直接指定项目的位置
grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
justify-self
/ align-self
/ place-self
justify-self
属性设置单元格内容的水平位置(左中右),跟justify-items
属性的用法完全一致,
但只作用于单个项目 (水平方向)
align-self
属性设置单元格内容的垂直位置(上中下),跟align-items
属性的用法完全一致,
也是只作用于单个项目 (垂直方向)
justify-self: start | end | center | stretch;
align-self: start | end | center | stretch;
place-self
属性是align-self
属性和justify-self
属性的合并简写形式place-self: center center;
两栏布局
两栏布局实现效果就是将页面分割成左右宽度不等的两列,宽度较小的列设置为固定宽度,剩余宽度由另一列撑满。
比如 Ant Design
文档,蓝色区域为主要内容布局容器,侧边栏为次要内容布局容器
这里称宽度较小的列父元素为次要布局容器,宽度较大的列父元素为主要布局容器
margin实现
实现思路也非常的简单:
- 使用 float 左浮左边栏
- 右边模块使用 margin-left 撑出内容块做内容展示
- 为父级元素添加BFC,防止下方元素飞到上方内容
代码如下:
<style>
.box{
overflow: hidden; 添加BFC
}
.left {
float: left;
width: 200px;
background-color: gray;
height: 400px;
}
.right {
margin-left: 210px;
background-color: lightgray;
height: 200px;
}
</style>
<div class="box">
<div class="left">左边</div>
<div class="right">右边</div>
</div>
还有一种更为简单的使用则是采取:flex弹性布局
overflow实现
.box {
height: 200px;
}
.box > div {
height: 100%;
}
.box-left {
width: 200px;
float: left;
background-color: blue;
}
.box-right {
overflow: hidden;
background-color: red;
}
flex弹性布局
<style>
.box{
display: flex;
}
.left {
width: 100px;
}
.right {
flex: 1;
}
</style>
<div class="box">
<div class="left">左边</div>
<div class="right">右边</div>
</div>
flex
可以说是最好的方案了,代码少,使用简单
注意:
flex
容器的一个默认属性值:align-items: stretch;
这个属性导致了列等高的效果。 为了让两个盒子高度自动,需要设置:
align-items: flex-start
三栏布局
实现三栏布局中间自适应的布局方式有:
- 两边使用 float,中间使用 margin
- 两边使用 absolute,中间使用 margin
- 两边使用 float 和负 margin
- display: table 实现
- flex实现
- grid网格布局
两边使用 float,中间使用 margin
需要将中间的内容放在html
结构最后,否则右侧会呈现在中间内容的下方
实现代码如下:
<style>
.wrap {
background: #eee;
overflow: hidden; <!-- 生成BFC,计算高度时考虑浮动的元素 -->
padding: 20px;
height: 200px;
}
.left {
width: 200px;
height: 200px;
float: left;
background: coral;
}
.right {
width: 120px;
height: 200px;
float: right;
background: lightblue;
}
.middle {
margin-left: 220px;
height: 200px;
background: lightpink;
margin-right: 140px;
}
</style>
<div class="wrap">
<div class="left">左侧</div>
<div class="right">右侧</div>
<div class="middle">中间</div>
</div>
原理如下:
- 两边固定宽度,中间宽度自适应。
- 利用中间元素的margin值控制两边的间距
- 宽度小于左右部分宽度之和时,右侧部分会被挤下去
这种实现方式存在缺陷:
- 主体内容是最后加载的。
- 右边在主体内容之前,如果是响应式设计,不能简单的换行展示
两边使用 absolute,中间使用 margin
基于绝对定位的三栏布局:注意绝对定位的元素脱离文档流,相对于最近的已经定位的祖先元素进行定位。无需考虑HTML中结构的顺序
<style>
.container {
position: relative;
}
.left,
.right,
.main {
height: 200px;
line-height: 200px;
text-align: center;
}
.left {
position: absolute;
top: 0;
left: 0;
width: 100px;
background: green;
}
.right {
position: absolute;
top: 0;
right: 0;
width: 100px;
background: green;
}
.main {
margin: 0 110px;
background: black;
color: white;
}
</style>
<div class="container">
<div class="left">左边固定宽度</div>
<div class="right">右边固定宽度</div>
<div class="main">中间自适应</div>
</div>
实现流程:
- 左右两边使用绝对定位,固定在两侧。
- 中间占满一行,但通过 margin和左右两边留出10px的间隔
两边使用 float 和负 margin
<style>
.left,
.right,
.main {
height: 200px;
line-height: 200px;
text-align: center;
}
.main-wrapper {
float: left;
width: 100%;
}
.main {
margin: 0 110px;
background: black;
color: white;
}
.left,
.right {
float: left;
width: 100px;
margin-left: -100%;
background: green;
}
.right {
margin-left: -100px; /* 同自身宽度 */
}
</style>
<div class="main-wrapper">
<div class="main">中间自适应</div>
</div>
<div class="left">左边固定宽度</div>
<div class="right">右边固定宽度</div>
实现过程:
- 中间使用了双层标签,外层是浮动的,以便左中右能在同一行展示
- 左边通过使用负 margin-left:-100%,相当于中间的宽度,所以向上偏移到左侧
- 右边通过使用负 margin-left:-100px,相当于自身宽度,所以向上偏移到最右侧
缺点:
- 增加了 .main-wrapper 一层,结构变复杂
- 使用负 margin,调试也相对麻烦
使用 display: table 实现
<table>
标签用于展示行列数据,不适合用于布局。但是可以使用 display: table
来实现布局的效果
<style>
.container {
height: 200px;
line-height: 200px;
text-align: center;
display: table;
table-layout: fixed;
width: 100%;
}
.left,
.right,
.main {
display: table-cell;
}
.left,
.right {
width: 100px;
background: green;
}
.main {
background: black;
color: white;
width: 100%;
}
</style>
<div class="container">
<div class="left">左边固定宽度</div>
<div class="main">中间自适应</div>
<div class="right">右边固定宽度</div>
</div>
实现原理:
- 层通过 display: table设置为表格,设置 table-layout: fixed`表示列宽自身宽度决定,而不是自动计算。
- 内层的左中右通过 display: table-cell设置为表格单元。
- 左右设置固定宽度,中间设置 width: 100% 填充剩下的宽度
使用flex实现
利用flex
弹性布局,可以简单实现中间自适应
代码如下:
<style type="text/css">
.wrap {
display: flex;
justify-content: space-between;
}
.left,
.right,
.middle {
height: 100px;
}
.left {
width: 200px;
background: coral;
}
.right {
width: 120px;
background: lightblue;
}
.middle {
background: #555;
width: 100%;
margin: 0 20px;
}
</style>
<div class="wrap">
<div class="left">左侧</div>
<div class="middle">中间</div>
<div class="right">右侧</div>
</div>
实现过程:
- 仅需将容器设置为
display:flex;
, - 盒内元素两端对其,将中间元素设置为
100%
宽度,或者设为flex:1
,即可填充空白 - 盒内元素的高度撑开容器的高度
优点:
- 结构简单直观
- 可以结合 flex的其他功能实现更多效果,例如使用 order属性调整显示顺序,让主体内容优先加载,但展示在中间
grid网格布局
代码如下:
<style>
.wrap {
display: grid;
width: 100%;
grid-template-columns: 300px auto 300px;
}
.left,
.right,
.middle {
height: 100px;
}
.left {
background: coral;
}
.right {
background: lightblue;
}
.middle {
background: #555;
}
</style>
<div class="wrap">
<div class="left">左侧</div>
<div class="middle">中间</div>
<div class="right">右侧</div>
</div>
跟flex
弹性布局一样的简单