此文包括的布局类型有:未知宽高元素的水平垂直居中、 两栏等高、两栏布局、三栏布局(包括双飞翼布局和圣杯布局),三栏布局之固定高度中间自适应,除了代码外,还有笔者的一点个人理解,若是有所错误或不足的,欢迎大家指出!
未知宽高元素的水平垂直居中
"container">
"ele">hello world
为了便于观察,先设置一些css样式:
.container {
width: 200px;
height: 200px;
background-color: #eee;
}
.ele {
background-color: rgb(179, 174, 174);
}
复制代码
将下面任一种方法的css样式分别添加到上面的代码中,都能得到下图这个效果。
方法一:绝对定位 + 平移
.contaienr {
position: relative;
}
.ele {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
// 若宽高已知,还可以使用margin-left,margin-right代替
}
复制代码
// 若是ele指定了宽高,还可以设置距上下左右都为0再自动间隔
// 若没有设置宽高就直接使用的话,ele的宽高都会是父元素的100%
.ele {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width: 100px;
height: 100px;
}
复制代码
方法二:tabel布局
.container {
display: table-cell;
text-align: center;
vertical-align: middle;
}
.ele {
display: inline-block; // 可选,若不加则ele的宽度将是父元素的100%
}
复制代码
方法三: flex布局
.container {
display: flex;
justify-content: center;
align-items: center;
}
复制代码
两栏等高
padding内补偿法
"box">
"left">
左浮动
左浮动
左浮动
"right">
也是左浮动
也是左浮动
也是左浮动
也是左浮动
也是左浮动
也是左浮动
.box {
overflow: hidden;
}
.left {
width: 50px;
float: left;
background-color: yellow;
padding-bottom: 2000px;
margin-bottom: -2000px;
}
.right {
width: 100px;
float: left;
background-color: red;
padding-bottom: 2000px;
margin-bottom: -2000px;
}
复制代码
两栏等高的原理是,给每一栏都设置一个很大的
padding-bottom
的值,以此来弥补高度较小的那一栏。再使用一个等大的负的margin-bottom
来收缩,正如我在另一篇文章里我解释的,使用负margin-bottom收缩后,虽然元素自身的宽高没有改变,但它的元素框会随着减小,最终元素框的高度取决于两栏中较高一栏。这时如果给它们的父元素添加overflow: hidden
,则会隐藏掉溢出元素框的部分内容,于是就达到了高度较低的一栏和较高的一栏等高的效果。
但是使用padding内补偿法有一个缺陷,如果每一栏设置了border的话,因为每一栏的高被padding撑高而且隐藏了超出的内容,所以border-bottom是显示不出来的。解决办法是,再在每一栏的最后一个子元素设置一个div来模仿border-bottom。记得还要给父元素box设置为相对定位,才能让伪border-bottom定位到那一栏的底部。
.border {
width: 52px;
height: 2px;
background-color: blue;
position: absolute;
bottom: 0;
}
复制代码
使用div模仿border-bottom还是有一个限制,就是必须先设置好那一栏的宽度,才好给border设置width。使用
width: calc(100% + 2px)
是没用的,因为每一栏都没有相对定位,所以100%是参考box而言的。如果要给每一栏设置相对定位,则border的绝对定位是相对于每一栏而言的,显示的边框又会被隐藏掉了。
tabel布局
利用表格(table)中每个单元格(table-cell)等高的特性
// IE8以下不支持
.box {
display: table;
overflow: hidden;
}
.left {
width: 50px;
background-color: yellow;
display: table-cell;
}
.right {
width: 100px;
background-color: red;
display: table-cell;
}
复制代码
flex布局
.box {
display: flex;
}
.left {
background-color: blue;
width: 100px;
}
.right {
background-color: yellow;
}
复制代码
js / jq动态设置
在js代码里去获取box里每一栏的高度并取它们的最大值,再将每一栏的高度设置为该最大值。但这不可避免会操作到DOM,难免对性能造成影响。
两栏布局
左栏固定宽度,右栏自适应。
利用负margin
实现逻辑请看盒模型和负margin这篇文章里的解释。
"box">
"slider">
slider
"content">
content
content
content
content
.box {
overflow: hidden
}
.slider {
float: left;
width: 100px;
height: 200px;
background-color: blue;
}
.content {
float: left;
width: 100%;
height: 200px;
background-color: yellow;
margin-right: -100px;
}
.content p {
margin-right: 100px;
}
复制代码
"box">
"content">
content
content
content
content
"slider">
slider
.slider {
float: left;
width: 100px;
height: 200px;
background-color: blue;
margin-left: -100%;
}
.content {
float: left;
width: 100%;
height: 200px;
background-color: yellow;
}
.content p {
margin-left: 100px;
}
复制代码
绝对定位
两栏都绝对定位并使用calc计算自适应那一栏的宽度
"box">
"slider">
slider
"content">
content
content
content
content
.box {
position: relative;
}
.slider {
width: 100px;
height: 200px;
background-color: blue;
position: absolute;
left: 0;
}
.content {
width: 100%;
height: 200px;
background-color: yellow;
position: absolute;
left: 100px;
}
复制代码
tabel布局
利用表格的宽度等于所有单元格宽度之和的特性
"box">
"slider">
slider
"content">
content
content
content
content
.box {
display: table;
width: 100%;
}
.slider {
width: 100px;
display: table-cell;
background-color: blue;
}
.content {
display: table-cell;
background-color: yellow;
}
复制代码
flex布局
flex大法真香
"box">
"slider">
slider
"content">
content
content
content
content
.box {
display: flex;
}
.slider {
background-color: blue;
width: 100px;
}
.content {
background-color: yellow;
flex: 1;
}
复制代码
grid布局
"box">
"slider">
slider
"content">
content
content
content
content
.box {
display: grid;
grid-template-rows: 100px;
grid-template-columns: 100px auto;
}
.slider {
background-color: blue;
}
.content {
background-color: yellow;
}
复制代码
三栏布局
跟两栏布局差不多,三栏布局是左右两栏固定宽度,中间栏自适应宽度(即固比固布局)。
浮动
"box">
"left">
我是左导航栏我是左导航栏我是左导航栏
"right">
我是右导航栏我是右导航栏我是右导航栏
"content">
"inner-content">
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
.content {
background-color: blue;
}
.inner-content {
margin-left: 100px;
margin-right: 100px;
}
.left {
float: left;
width: 100px;
background-color: red;
}
.right {
float: right;
width: 100px;
background-color: yellow;
}
复制代码
从效果图中可以看出,使用浮动实现三栏布局在中间栏容纳得下内容时是可以正常工作的,但内容一旦超出,中间栏就会向下扩展。如果给它们指定 height 的话自然就不存在这问题了,不过内容还是会溢出来的(见下图)。当然我们可以选择给外层容器box设置
overflow: hidden
来隐藏,但如果我们要显示全部内容的话要怎么办?答案是给左中右三个元素使用padding内补偿法,使它们三栏等高。(当浏览器宽度小于左右两栏的宽度和时,右栏会被挤下来,这时要也只能去给 body 设置min-width
了,这点跟圣杯布局一样)。
绝对定位
"box">
"left">
我是左导航栏我是左导航栏我是左导航栏
"content">
"inner-content">
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
"right">
我是右导航栏我是右导航栏我是右导航栏
.box {
position: relative;
}
.content {
background-color: blue;
}
.inner-content {
margin-left: 100px;
margin-right: 100px;
}
.left {
width: 100px;
background-color: red;
position: absolute;
left: 0;
top: 0;
}
.right {
width: 100px;
background-color: yellow;
position: absolute;
right: 0;
top: 0;
}
复制代码
也存在内容大于中间栏宽度,中间栏会向下扩展的问题。
flex布局
"box">
"left">
我是左导航栏我是左导航栏我是左导航栏
"content">
"inner-content">
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
"right">
我是右导航栏我是右导航栏我是右导航栏
.box {
display: flex;
}
.content {
background-color: blue;
flex: 1;
}
.left {
width: 100px;
background-color: red;
}
.right {
width: 100px;
background-color: yellow;
}
复制代码
对高度会自适应,内容超出时三栏会自动调整高度。
tabel布局
"box">
"left">
我是左导航栏我是左导航栏我是左导航栏
"content">
"inner-content">
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
"right">
我是右导航栏我是右导航栏我是右导航栏
.box {
display: table;
width: 100%;
}
.content {
background-color: blue;
display: table-cell;
}
.left {
width: 100px;
background-color: red;
display: table-cell;
}
.right {
width: 100px;
background-color: yellow;
display: table-cell;
}
复制代码
对高度会自适应,内容超出时三栏会自动调整高度。
grid布局
"box">
"left">
我是左导航栏我是左导航栏我是左导航栏
"content">
"inner-content">
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
"right">
我是右导航栏我是右导航栏我是右导航栏
.box {
display: grid;
grid-template-columns: 100px auto 100px;
}
.content {
background-color: blue;
}
.left {
background-color: red;
}
.right {
background-color: yellow;
}
复制代码
对高度会自适应,内容超出时三栏会自动调整高度。
双飞翼布局
"box">
"content">
"inner-content">
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
"left">
我是左导航栏我是左导航栏我是左导航栏
"right">
我是右导航栏我是右导航栏我是右导航栏
.left {
width: 100px;
height: 100px;
background-color: red;
float: left;
margin-left: -100%;
}
.right {
width: 100px;
height: 100px;
background-color: yellow;
float: left;
margin-left: -100px;
}
.content {
width: 100%;
height: 100px;
float: left;
background-color: blue;
}
.inner-content {
margin-left: 100px;
margin-right: 100px;
}
复制代码
同样是使用浮动,但双飞翼布局是对负margin的应用,实现详情请看负margin实现两栏布局。同样的是,在HTML代码部分也是把content放到left和right前面的优先渲染 ,否则left放前面的话会造成left被content覆盖或是内容超出视图,也存在前面的那两个问题。听说双飞翼布局是淘宝创造的?
圣杯布局
"box">
"content">
"inner-content">
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
"left">
我是左导航栏我是左导航栏我是左导航栏
"right">
我是右导航栏我是右导航栏我是右导航栏
body {
min-width: 400px;
}
.box {
padding: 0 100px 0 100px;
}
.left {
width: 100px;
height: 100px;
background-color: red;
float: left;
margin-left: -100%;
position: relative;
left: -100px;
}
.right {
width: 100px;
height: 100px;
background-color: yellow;
float: left;
margin-left: -100px;
position: relative;
right: -100px;
}
.content {
width: 100%;
height: 100px;
float: left;
background-color: blue;
}
复制代码
圣杯布局和双飞翼布局同样是对负margin的应用,区别在于解决中间栏内容不被左右侧边栏遮挡的方法不同。双飞翼布局是直接给content设置一个子div,利用margin-left和margin-right来间隔开彼此。而圣杯布局给父容器box设置padding来间隔开content主体内容和左右的距离,再给左右两栏分别相对定位设置left和right使其回到原先的位置。圣杯布局潜在的问题是,但浏览器缩小到一定程度后,左右两栏会被挤下来,不过可以给body设置
min-width
来解决这个问题。个人比较推荐双飞翼布局,两者实现的效果是一样的,而圣杯布局又要用到相对定位甚至min-width,为什么不简单点直接用margin解决同样的问题呢,不仅思路简单些代码也简洁。
三栏布局总结
-
普通的浮动布局和双飞翼布局圣杯布局: 在 HTML 代码上普通的浮动是把中间栏放到最后,左右两栏分别左右浮动后中间空出来的空间给中间栏。而双飞翼布局和圣杯布局是把中间栏放在最前面使其先渲染,让三栏都左浮动后再利用左栏
margin-left: -100%
,右栏margin-left: -100px
使其都并排布局。 因为普通浮动里是把中间栏放到最后才渲染的,所以当页面内容较多时可能会影响用户体验。 -
对高度的适应性: 如果没有设置高度,flex布局,table布局,grid布局对三栏的高度变化有适应性,即使内容超出了三栏会都自动扩大自身高度来适应。而浮动和绝对定位两种方法内容一旦超出,中间栏则会向下扩展,双飞翼布局也一样有这问题,可以直接设置height来避免这问题。或者使用padding内补偿法使三栏都等高。
-
局限性: 浮动和绝对定位脱离文档流,需要处理好和其他元素的位置关系,不过兼容性比较好。
flex布局和grid布局是新生的布局方式,功能强大对高度的适应性好,但对浏览器的兼容性不是很好。
table布局适应性好,对浏览器的兼容性也好,但table布局好像一直受人诟病,似乎毛病很多?我没在项目里用到过,也不知道真假。
三栏布局之固定高度中间自适应
上下固定高度,中间自适应。都需要使用
overflow: scroll
来使中间栏溢出的部分在内部滚动,否则中间栏会扩展自身高度把底栏挤出视图,这我也不知道有什么更好的解决办法了。
绝对定位
"box">
"top">
我是头部
我是头部
我是头部
我是头部
"content">
"inner_content">
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
"bottom">
我是底部
我是底部
我是底部
.box {
width: 100%;
height: 100vh;
position: relative;
}
.content {
width: 100%;
height: 100%;
background-color: blue;
overflow: scroll;
}
.top {
width: 100%;
height: 100px;
background-color: red;
position: absolute;
left: 0;
top: 0;
}
.bottom {
width: 100%;
background-color: yellow;
position: absolute;
left: 0;
bottom: 0;
}
.inner_content {
padding-top: 100px;
}
复制代码
此处使用绝对定位有一个局限,需要事先知道顶部栏的高度,才好给中间栏的内容部分设置
padding-top
,否则内容会被顶部栏遮住。对于中间栏需要使用overflow: scroll
来使溢出部分在中间栏里滚动,否则中间栏会向下扩展。
flex布局
"box">
"top">
我是头部
我是头部
我是头部
"content">
"inner_content">
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
"bottom">
我是底部
我是底部
我是底部
.box {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
}
.content {
width: 100%;
flex: 1;
background-color: blue;
overflow: scroll;
}
.top {
width: 100%;
background-color: red;
}
.bottom {
width: 100%;
background-color: yellow;
}
复制代码
中间栏同样需要使用
overflow: scroll
。
grid布局
"box">
"top">
我是头部
我是头部
我是头部
"content">
"inner_content">
我是内容主题部分
我是内容主题部分
我是内容主题部分
我是内容主题部分
"bottom">
我是底部
我是底部
我是底部
.box {
width: 100%;
height: 100vh;
display: grid;
grid-template-rows: 100px auto 100px;
grid-template-columns: 100%;
}
.content {
background-color: blue;
}
.top {
background-color: red;
}
.bottom {
background-color: yellow;
}
复制代码
中间栏同样需要使用
overflow: scroll
。
收官
笔者暂时只想到这些常见的布局,若是有所缺漏的,欢迎大家指出,笔者会再做补充。
最后附Blog原文 和 笔者Github,欢迎大家一起交流学习~