26

一、简介

网页布局对于一个前端开发者而言至关重要,掌握好布局知识有助于我们更好的实现CSS界面的设计和开发。布局是有限空间内的元素排列方式,因为页面设计横向不滚动,纵向无限延伸,所以大多数时候讨论的布局都是对水平方向进行分割。常用的布局方式为单列布局两列布局三列布局粘连布局等。

二、单列布局

单列表布局是将一个元素作为布局容器,通常设置一个较小的(最大)宽度来保证不同像素宽度屏幕下显示一致。

<body>
    <div class="header">头部</div>
    <div class="content">单列布局</div>
    <div class="footer">底部</div>
</body>
<style>
body{
    margin: 0;
    padding: 0;
}
.header {
    margin: 0 auto;
    max-width: 720px;
    height: 100px;
    background: red;
}
.content {
    margin: 0 auto; /*宽度足够的时候元素居中显示*/
    max-width: 720px; /*设置一个最大宽度,保证各种屏幕显示一致*/
    height: 400px;
    background: green;
}
.footer {
    margin: 0 auto;
    max-width: 720px;
    height: 100px;
    background: blue;
}
</style>

单列布局效果图
单列布局的优势在于基本上可以适配超过布局容器宽度的各种显示屏幕,可以保证在超过设置的最大宽度的屏幕上浏览网站看到的效果是一致的。而它的缺点就是屏幕空间的浪费,在屏幕空间足够大的情况下,页面两侧显示了大量空白,如果屏幕特别大,两侧空白的区域可能会比页面内容更宽。

二、两列布局

两列布局就是将页面分割成左右宽度不等的两列宽度较小的列设置为固定宽度剩余宽度由另一列撑满。这种布局适用于内容上具有明显主次关系的网页
① float + margin方式
通过让左侧浮动,然后给右侧设置一个margin-left值为左侧元素的宽度即可。

<div class="container">
    <div class="left">
        左侧定宽
    </div>
    <div class="right">
        右侧自适应
    </div>
</div>
<style>
    .container {
        min-width: 500px;
        height: 100px;
    }
    .left {
        background: red;
        width: 200px;
        height: 100px;
        float: left; /*让左侧元素浮动*/

    }
    .right {
        background: green;
        height: 100px;
        margin-left: 200px; /*给右侧元素添加一个margin-left,为左侧区域留出空间*/
    }
</style>

② 绝对定位
首先给父容器设置一个相对定位,然后给左侧元素设置一个绝对定位给右侧也设置一个绝对定位left值为左侧元素的宽度right值为0,即可。

<style>
.container {
    height: 100px;
    min-width: 500px;
    position: relative; /*父容器设置为相对定位*/
}
.left {
    background: red;
    width: 200px;
    height: 100px;
    position: absolute;
    left: 0;
}
.right {
    background: green;
    height: 100px;
    position: absolute;
    left: 200px; /*值为左侧定宽元素的宽度*/
    right: 0; /*同时设置left和right可以实现宽度的自适应效果*/
}
</style>

③ Float + BFC
所谓BFC就是Block fomatting context(块级格式化上下文),对于BFC盒子而言,其拥有一个独立的布局环境BFC容器里面的子元素不会影响到外面的元素,反之亦是如此。
BFC容器相对于普通的盒子而言,有一些特性:
a. 在同一个文档流中BFC的区域不会与float box重叠
b. 为了不影响BFC容器外元素的布局计算BFC的高度时,浮动元素也会参与计算

如何让一个普通的盒子变成BFC容器?

  • float的值不是none
  • position的值不是static或者relative
  • display的值是inline-block、table-cell、flex、table-caption或者inline-flex
  • overflow的值不是visible
<style>
.container {
    height: 100px;
    min-width: 500px;
}
.left {
    background: red;
    width: 200px;
    height: 100px;
    float: left;/*左侧浮动*/
}
.right {
    background: green;
    height: 100px;
    overflow: hidden; /*让右侧变成一个BFC容器,避免与左侧浮动元素重合 */
}
</style>

④ Flex实现
主要就是给父容器设置成flex布局容器,然后给右侧设置flex为1即可让右侧变成自适应。

<style>
.container {
    height: 100px;
    min-width: 500px;
    display: flex; /*给父容器设置为flex容器*/
}
.left {
    background: red;
    width: 200px;
    height: 100px;
}
.right {
    background: green;
    height: 100px;
    flex: 1; /*给右侧设置成自适应*/
}
</style>

三、三列布局

三列布局按照左中右的顺序进行排列,通常中间列最宽(自适应)左右两列次之。三列布局相对复杂些,我们会按步骤一步一步实现,如:
① 圣杯布局

<div class="container">
    <div class="main">圣杯布局</div>
    <div class="left">left</div>
    <div class="right">right</div>
</div>

所谓圣杯布局,就是根据左右两侧元素的宽度给父容器元素设置一个左右内边距,为了方便记忆,我们可以理解成一开始父容器内是方形填满的,给父容器添加左右内边距,我们可以想象成将圣杯压缩成形的过程

<style>
.container {
    background: yellow;
    height: 100px;
    padding: 0px 100px 0px 150px; /*父元素添加内边距将圣杯压缩成形*/
}
.main {
    background: green;
    width: 100%;
    height: 100px;
}
.left {
    background: red;
    width: 150px;
    height: 100px;
}
.right {
    background: blue;
    width: 100px;
    height: 100px;
}
</style>

image
因为目前左右两部分都在内容的垂直排列,所以接下来需要给左中右三部分都添加一个左浮动让三个元素水平排在一起,需要注意的是三个元素进行左浮动之后,左右两个元素仍然在中间元素的下面,因为中间元素设置的宽度是100%,所以中间元素会占满父元素,由于宽度无法容下左右两块元素,所以左右两块元素会换行排列在一起,如:

<style>
    .main {
        float: left; /*让三个元素水平排列在一起*/
    }
    .left {
        float: left; /*让三个元素水平排列在一起*/
    }
    .right {
        float: left; /*让三个元素水平排列在一起*/
    }
</style>

image

此时左中右三个元素可以看做是水平排列在一起的,我们可以通过给左右两块元素设置一个负的margin-left即可让左右两块元素向左边移动左侧元素需要到最左边去,故其margin-left值为-100%,即中间元素的宽度,右侧元素需要到最右边去,故其margin-left值为负的右侧元素自身宽度

<style>
    .left {
        margin-left: -100%; /*将左侧元素移动中间元素的宽度,到最左边去*/
    }
    .right {
        margin-left: -100px; /*将右侧元素移动负的自身宽度,到最右边去*/
    }
</style>

image

此时已经可以看到左中右三个元素水平排列在一起,并且左侧元素在最左边,右侧元素在最右边,但是左侧元素其实应该是要在左侧黄色区域中,右侧元素应该在右侧黄色区域中才对,所以我们需要给左右两个元素一个相对定位。左侧元素再向左移动自身宽度的距离,故其left值为负的左侧元素自身宽度,右侧元素需要右侧移动自身宽度的距离,故其right值为负的右侧元素自身宽度

<style>
    .left {
        position: relative; /*设置一个相对定位*/
        left: -150px; /*相对于当前位置向左移动负的自身宽度*/
    }
    .right {
        position: relative; /*设置一个相对定位*/
        right: -100px; /*相对于当前位置向右移动负的自身宽度*/
    }
</style>

image
接下来我们调整浏览器的宽度,发现元素发生了布局错乱,因为当浏览器宽度特别小的时候,容器元素也会跟着变小,而左侧元素由于是浮动的左侧元素要想上来,必须向左移动一个负的自身宽度,由于左侧元素的margin-left值为-100%,即移动了容器的可用内容宽度当容器的可用内容宽度小于左侧元素的宽度的时候(容器的100%值 < 左侧元素的自身宽度),左侧元素将无法浮上来,只能换行显示。
image
而要想解决这个问题,我们就需要给容器设置一个最小宽度,这个最小宽度值怎么定呢?左侧元素要想不换行显示,那么容器的宽度必须能够容纳左侧元素的大小,所以容器内容区的最小值为左侧元素的宽度

.container {
    min-width: 150px; /*给容器设置一个最小宽度,值为左侧元素的宽度,防止换行显示*/
}

完整样式为:

<style>
    .container {
        background: yellow;
        height: 100px;
        padding: 0px 100px 0px 150px; /*父元素添加内边距将圣杯压缩成形*/
        min-width: 150px; /*给容器设置一个最小宽度,值为左侧元素的宽度,防止换行显示*/
    }
    .main {
        background: green;
        width: 100%;
        height: 100px;
        float: left; /*让三个元素水平排列在一起*/
    }
    .left {
        background: red;
        width: 150px;
        height: 100px;
        float: left; /*让三个元素水平排列在一起*/
        margin-left: -100%; /*将左侧元素移动中间元素的宽度,到最左边去*/
        position: relative; /*设置一个相对定位*/
        left: -150px; /*相对于当前位置向左移动负的自身宽度*/
    }
    .right {
        background: blue;
        width: 100px;
        height: 100px;
        float: left; /*让三个元素水平排列在一起*/
        margin-left: -100px; /*将右侧元素移动负的自身宽度,到最右边去*/
        position: relative; /*设置一个相对定位*/
        right: -100px; /*相对于当前位置向右移动负的自身宽度*/
    }
</style>

② 双飞翼布局

<div class="container">
    <div class="main">
        <div class="content">双飞翼布局</div>
    </div>
    <div class="left">left</div>
    <div class="right">right</div>
</div>

所谓双飞翼布局,就是给中间元素包裹一层div盒子,然后根据左右两侧元素的宽度给中间内容元素设置一个左右外边距,为了方便记忆,我们可以理解成,给中间添加左右外边距,就像给中间元素加装了一双翅膀,从而形成双飞翼布局。

<style>
    .container {
        background: yellow;
        height: 100px;
    }
    .main {
        width: 100%;
    }
    .content {
        background: green;
        height: 100px;
        margin-left: 150px; /*给中间元素添加一个左外边距(翅膀)*/
        margin-right: 100px; /*给中间元素添加一个右外边距(翅膀)**/
    }
    .left {
        background: red;
        width: 150px;
        height: 100px;
    }
    .right {
        background: blue;
        width: 100px;
        height: 100px;
    }
</style>

image

同样的,需要给左中右三部分都添加一个左浮动让三个元素水平排在一起,如:

<style>
    .main {
        float: left; /*让三个元素水平排列在一起*/
    }
    .left {
        float: left; /*让三个元素水平排列在一起*/
    }
    .right {
        float: left; /*让三个元素水平排列在一起*/
    }
</style>

image
同样的,需要给左侧添加一个负的margin-left,值为-100%,给右侧添加一个负的margin-left,值为负的右侧元素自身宽度大小
由于之前中间元素已经设置好了左右外边距给左右两个元素留出了位置,所以添加margin-left之后就已经实现了。

<style>
    .left {
        margin-left: -100%; /*将左侧元素移动中间元素的宽度,到最左边去*/
    }
    .right {
        margin-left: -100px; /*将右侧元素移动负的自身宽度,到最右边去*/
    }
</style>

image
同样的为了防止容器宽度太小导致左右两个元素换行显示,需要设置一个最小宽度。

.container {
    min-width: 400px; /*给容器设置一个最小宽度,值为左侧元素的宽度,防止换行显示*/
}

完整样式如下:

<style>
    .container {
        background: yellow;
        height: 100px;
        min-width: 400px; /*给容器设置一个最小宽度,值为左侧元素的宽度,防止换行显示*/
    }
    .main {
        float: left;
        width: 100%;
    }
    .content {
        background: green;
        height: 100px;
        margin-left: 150px; /*给中间元素添加一个左外边距(翅膀)*/
        margin-right: 100px; /*给中间元素添加一个右外边距(翅膀)**/
    }
    .left {
        background: red;
        width: 150px;
        height: 100px;
        float: left;
        margin-left: -100%; /*将左侧元素移动中间元素的宽度,到最左边去*/
    }
    .right {
        background: blue;
        width: 100px;
        height: 100px;
        float: left;
        margin-left: -100px; /*将右侧元素移动负的自身宽度,到最右边去*/
    }
</style>

③ Flex实现三列布局
Flex实现三列布局相对简单些,就是将父容器设置为flex容器中间元素设置flex值为1,让其自适应剩余宽度,将左右元素设置为禁止缩小,即flex-shrink值设置为0.

<div class="container">
    <div class="left">left</div>
    <div class="main">flex三列布局</div>
    <div class="right">right</div>
</div>
<style>
    .container {
        background: yellow;
        height: 100px;
        display: flex; /*将父容器设置为flex布局*/
    }
    .main {
        background: green;
        height: 100px;
        flex: 1; /*自适应剩余宽度*/
        min-width: 150px; /*给中间元素设置一个最小宽度防止过度缩放导致布局错乱*/
    }
    .left {
        background: red;
        width: 150px;
        height: 100px;
        flex-shrink: 0; /*禁止缩小*/
    }
    .right {
        background: blue;
        width: 100px;
        height: 100px;
        flex-shrink: 0; /*禁止缩小*/
    }
</style>

四、sticky footer粘连布局

所谓粘连布局,就是将页面分成上、中、下三个部分,上、下部分都为固定高度中间部分高度不定(但有一个最小高度为浏览器高度),当页面高度小于浏览器高度时,下部分应固定在屏幕底部,当页面高度超出浏览器高度时,下部分应该随中间部分被撑开,显示在页面最底部
① margin-top + padding-bottom实现
首先布局上将footer部分放到container容器下面,header和main放到container容器的中。

<div class="container">
    <div class="header">header</div>
    <div class="main">
        <h1>Sticky Footer粘连布局</h1>
        <button id="add">添加内容</button>
    </div>
</div>
<div class="footer">footer</div>
<script>
    const addButton = document.getElementById("add");
    const main = document.querySelector(".main");
    addButton.onclick = function() {
        const p = document.createElement("p");
        p.innerText = "粘连布局内容";
        main.appendChild(p);
    }
</script>
<style>
* {
    padding: 0;
    margin: 0;
}
html, body {
    height: 100%;
}
.container {
    min-height: 100%; /*整个容器撑满整个浏览器的高度*/
}
.header {
    background: red;
    height: 100px;
}
.main {
    background: green;
}   
.footer {
    background: blue;
    height: 100px;
}
</style>

目前由于container容器设置了min-height为100%,所以footer部分会被挤压到浏览器底部的下面。接下来我们就需要让footer部分上移到浏览器的底部,可以通过给footer设置一个margin-top,值为负的footer自身高度

.footer {
    margin-top: -100px; /*让footer上移到浏览器的底部*/
}

image
此时点击添加内容按钮,添加一些内容,可以看到添加的内容会覆盖footer区域,如:
image
之所以出现这种情况,是因为footer通过margin-top上移后只是覆盖在了container上面,所以需要给container容器设置一个padding-bottom,将container容器的内容区上移

* {
    box-sizing: border-box; /*将所有元素都定义成border-box边框盒模型,非常重要*/
}
.container {
    padding-bottom: 100px; /*将container的内容区向上移动footer高度的距离*/
}

需要注意的是,我们给container容器添加padding-bottom之后,为不影响整个container容器的高度需要将container容器设置成边框盒模型
image

完整样式代码如下:

<style>
* {
    padding: 0;
    margin: 0;
    box-sizing: border-box; /*将所有元素都定义成border-box边框盒模型,非常重要*/
}
html, body {
    height: 100%;
}
.container {
    min-height: 100%; /*整个容器撑满整个浏览器的高度*/
    padding-bottom: 100px; /*将container的内容区向上移动footer高度的距离*/
}
.header {
    background: red;
    height: 100px;
}
.main {
    background: green;
}   
.footer {
    background: blue;
    height: 100px;
    margin-top: -100px; /*让footer上移到浏览器的底部*/
}
</style>

② 通过flex布局实现
布局上有所不同,会将header、main和footer都放到container容器的中,并将container容器设置为flex布局,给container容器设置一个最小高度为浏览器高度即100%,然后给中间部分设置flex值为1自适应将footer撑开到浏览器底部,等中间内容过多的时候就会将footer往下推。

<div class="container">
    <div class="header">header</div>
    <div class="main">
        <h1>Sticky Footer粘连布局</h1>
        <button id="add">添加内容</button>
    </div>
    <div class="footer">footer</div>
</div>
<script>
    const addButton = document.getElementById("add");
    const main = document.querySelector(".main");
    addButton.onclick = function() {
        const p = document.createElement("p");
        p.innerText = "粘连布局内容";
        main.appendChild(p);
    }
</script>
<style>
* {
    margin: 0;
}
html, body {
    height: 100%;
}
.container {
    min-height: 100%; /*给容器设置一个最小高度为100%,以便将footer撑到底部*/
    display: flex; /*将container容器设置成flex布局*/
    flex-direction: column; /*flex布局的方向设置为列*/
}
.header {
    background: red;
    height: 100px;
}
.main {
    background: green;
    flex: 1; /*让中间部分自适应,以便将footer撑到底部*/
}   
.footer {
    background: blue;
    height: 100px;
}
</style>

JS_Even_JS
2.6k 声望3.7k 粉丝

前端工程师