CSS技巧篇(十一):CSS布局

299 阅读10分钟

本文概要

本文将介绍如下几种常见的布局:

一、单列布局

常见的单列布局有两种:

  • header,content和footer等宽的单列布局
  • header与footer等宽,content略窄的单列布局

1.如何实现

对于第一种,先通过对header,content,footer统一设置width:1000px;或者max-width:1000px(这两者的区别是当屏幕小于1000px时,前者会出现滚动条,后者则不会,显示出实际宽度);然后设置margin:auto实现居中即可得到。

<div class="header"></div>
<div class="content"></div>
<div class="footer"></div>
.header{
    margin:0 auto; 
    max-width: 960px;
    height:100px;
    background-color: blue;
}
.content{
    margin: 0 auto;
    max-width: 960px;
    height: 400px;
    background-color: aquamarine;
}
.footer{
    margin: 0 auto;
    max-width: 960px;
    height: 100px;
    background-color: aqua;
}

对于第二种,header、footer的内容宽度不设置,块级元素充满整个屏幕,但header、content和footer的内容区设置同一个width,并通过margin:auto实现居中。

<div class="header">
    <div class="nav"></div>
</div>
<div class="content"></div>
<div class="footer"></div>
.header{
    margin:0 auto;
    max-width: 960px;
    height:100px;
    background-color: blue;
}
.nav{
    margin: 0 auto;
    max-width: 800px;
    background-color: darkgray;
    height: 50px;
}
.content{
    margin: 0 auto;
    max-width: 800px;
    height: 400px;
    background-color: aquamarine;
}
.footer{
    margin: 0 auto;
    max-width: 960px;
    height: 100px;
    background-color: aqua;
}

二、两列自适应布局

两列自适应布局是指一列由内容撑开,另一列撑满剩余宽度的布局方式

1.float+overflow:hidden

如果是普通的两列布局,浮动+普通元素的margin便可以实现,但如果是自适应的两列布局,利用float+overflow:hidden便可以实现,这种办法主要通过overflow触发BFC,而BFC不会重叠浮动元素。由于设置overflow:hidden并不会触发IE6-浏览器的haslayout属性,所以需要设置zoom:1来兼容IE6-浏览器。具体代码如下:

<div class="parent" style="background-color: lightgrey;">
    <div class="left" style="background-color: lightblue;">
        <p>left</p>
    </div>
    <div class="right"  style="background-color: lightgreen;">
        <p>right</p>
        <p>right</p>
    </div>        
</div>
.parent {
  overflow: hidden;
  zoom: 1;
}
.left {
  float: left;
  margin-right: 20px;
}
.right {
  overflow: hidden;
  zoom: 1;
}

注意点:如果侧边栏在右边时,注意渲染顺序。即在HTML中,先写侧边栏后写主内容

2.Flex布局

Flex布局,也叫弹性盒子布局,区区简单几行代码就可以实现各种页面的的布局。

//html部分同上
.parent {
  display:flex;
}  
.right {
  margin-left:20px; 
  flex:1;
}

3.grid布局

Grid布局,是一个基于网格的二维布局系统,目的是用来优化用户界面设计。

//html部分同上
.parent {
  display:grid;
  grid-template-columns:auto 1fr;
  grid-gap:20px
} 

三、三栏布局

特征:中间列自适应宽度,旁边两侧固定宽度

圣杯布局

其实我还真是第一次听说圣杯布局这种称呼,看了下这个名字的由来,貌似和布局并没有什么关系,圣杯布局倒是挺常见的三栏式布局。两边顶宽,中间自适应的三栏布局。
效果如下:
圣杯布局

这个布局方式的关键是怎么样才能使得在伸缩浏览器窗口的时候让中间的子元素宽度改变。可以适应浏览器的宽度变化使用百分比设置宽度再合适不过,所以我们要将中间子元素的宽度设置为 100%,左边和右边的子元素设置为固定的宽度。

我们就来实现一下这样的布局:

给出HTML结构

HTML 文件就很普通:

<div class="container">
    <div class="middle">测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试</div>
    <div class="left">left</div>
    <div class="right">right</div>
</div>

这里我们要注意的是,中间栏要在放在文档流前面以优先渲染。

给出每个子元素的样式

然后我们写 CSS,我们现将其三个元素的宽度和高度设置好,然后都设置为 float:left:

.middle{
    width: 100%;
    background: paleturquoise;
    height: 200px;
    float: left;
}
.left{
    background: palevioletred;
    width: 200px;
    height: 200px;
    float: left;
    font-size: 40px;
    color: #fff;
}
.right{
    width: 200px;
    height: 200px;
    background: purple;
    font-size: 40px;
    float: left;
    color: #fff;
}

这时的效果如下:
圣杯布局

使子元素在同一行显示

我们可以看出,现在三个子元素是在一排显示的,因为我们给中间的子元素设置的宽度是 100%,并且中间的子元素在文档流的最前面,最先被渲染。

那么我们要使得三个元素在同一排显示。接下来我们要将 .left.right 向上提。实际上我们是使用 margin-left 为 负值来实现的,我们将 .leftmargin-left 设置为 -100%(负的中间子元素的宽度),这样,左边的元素就会被“提升”到上一层。

然后就是右边子元素了,只需要设置 margin-left 设置为负的自身的宽度。

结果如下:
这里写图片描述

使得中间子元素不被遮盖

从上一张截图显示中显示中间的子元素被遮挡了,所以说我们要解决这个问题,要怎么解决呢?嗯... 只要使得中间的子元素显示的宽度刚好为左边元素和右边元素显示中间的宽度就可以。同时我们还必须保证是使用的半分比的布局方式。

这样的话有一种方式可以即使中间的宽度减少,又可以使中间的宽度仍然使用 100%,那就是设置父元素的 padding 值,将父元素的 padding-left 设置为左边子元素的宽度,将父元素的 padding-right 设置为右边子元素的宽度。

显示效果如下:
圣杯布局

将左边和右边的子元素像两边移动

嗯... 这貌似也不是我们想要的效果,但是,中间的子元素确实是在中间了,那么我们只需要设置相对位置,将左边的子元素和右边的子元素向两边移动就好。

最终的 CSS 代码如下:

.container{
    padding: 0 200px;
}
.middle{
    width: 100%;
    background: paleturquoise;
    height: 200px;
    float: left;
}
.left{
    background: palevioletred;
    width: 200px;
    height: 200px;
    float: left;
    font-size: 40px;
    color: #fff;
    margin-left:-100%;
    position:relative;
    left:-200px;

}
.right{
    width: 200px;
    height: 200px;
    background: purple;
    font-size: 40px;
    float: left;
    color: #fff;
    margin-left:-200px;
    position: relative;
    right: -200px;
}

最终效果如下: 圣杯布局

缺点

  • center部分的最小宽度不能小于left部分的宽度,否则会left部分掉到下一行
  • 如果其中一列内容高度拉长(如下图),其他两列的背景并不会自动填充

双飞翼布局

其实双飞翼布局是为了解决圣杯布局的弊端提出的,如果你跟我一起将上面的圣杯布局的代码敲了一遍,你就会发现一个问题,当你将浏览器宽度缩短到一定程度的时候,会使得中间子元素的宽度比左右子元素宽度小的时候,这时候布局就会出现问题。所以首先,这提示了我们在使用圣杯布局的时候一定要设置整个容器的最小宽度。

圣杯布局弊端

所以只是一个小小的改动同样也是三栏布局,在圣杯布局基础上进一步优化,解决了圣杯布局错乱问题,实现了内容与布局的分离。而且任何一栏都可以是最高栏,不会出问题。

<div class="container">
    <div class="middle-container">
        <div class="middle">测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试</div>

    </div>
    <div class="left">left</div>
    <div class="right">right</div>
</div>
.middle-container{
    width: 100%;
    background: paleturquoise;
    height: 200px;
    float: left;
}

.middle{
    margin-left: 200px;
    margin-right: 200px;
}
.left{
    background: palevioletred;
    width: 200px;
    height: 200px;
    float: left;
    font-size: 40px;
    color: #fff;
    margin-left:-100%;


}
.right{
    width: 200px;
    height: 200px;
    background: purple;
    font-size: 40px;
    float: left;
    color: #fff;
    margin-left:-200px;

}

这样,在我们将中间元素宽度调到比两边元素小的时候,也是可以正常显示,但是如果总宽度小于左边元素或者右边元素的时候,还是会有问题。
双飞翼布局

双飞翼和圣杯布局对比

  • 两种布局方式都是把主列放在文档流最前面,使主列优先加载。
  • 圣杯布局和双飞翼布局解决问题的方案在前一半是相同的,也就是三栏全部float浮动,但左右两栏加上负margin让其跟中间栏div并排,以形成三栏布局。
  • 不同在于解决”中间栏div内容不被遮挡“问题的思路不一样:圣杯布局,为了中间div内容不被遮挡,将中间div设置了左右padding-left和padding-right后,将左右两个div用相对布局position: relative并分别配合right和left属性,以便左右两栏div移动后不遮挡中间div。
  • 双飞翼布局,为了中间div内容不被遮挡,直接在中间div内部创建子div用于放置内容,在该子div里用margin-left和margin-right为左右两栏div留出位置。

四、等高布局

等高布局是指子元素在父元素中高度相等的布局方式。接下来我们介绍常见几种实现方式:

1.利用正padding+负margin

我们通过等布局便可解决圣杯布局的第二点缺点,因为背景是在 padding 区域显示的,设置一个大数值的 padding-bottom,再设置相同数值的负的 margin-bottom,并在所有列外面加上一个容器,并设置 overflow:hidden 把溢出背景切掉。这种可能实现多列等高布局,并且也能实现列与列之间分隔线效果,结构简单,兼容所有浏览器。新增代码如下:

.center,
.left,
.right {
padding-bottom: 10000px;
margin-bottom: -10000px;
}
.container {
padding-left: 220px;
padding-right: 220px;
overflow: hidden;//把溢出背景切掉
}

image

2.利用背景图片

这种方法是我们实现等高列最早使用的一种方法,就是使用背景图片,在列的父元素上使用这个背景图进行Y轴的铺放,从而实现一种等高列的假象。实现方法简单,兼容性强,不需要太多的css样式就可以轻松实现,但此方法不适合流体布局等高列的布局。

在制作样式之前需要一张类似下面的背景图:

<div class=”container clearfix”>
    <div class=”left”></div>
    <div  class=”content”></div>
    <div class=”right”></div>
</div>

.container {
  background: url("column.png") repeat-y;
  width: 960px;
  margin: 0 auto;
}
.left {
  float: left;
  width: 220px;
}
.content {
  float: left;
  width: 480px;
}
.right {
  float: left;
  width: 220px;
}

3.模仿表格布局

这是一种非常简单,易于实现的方法。不过兼容性不好,在ie6-7无法正常运行。

<div class="container table">
  <div class="containerInner tableRow">
    <div class="column tableCell cell1">
      <div class="left aside">
        ....
      </div>
    </div>
    <div class="column tableCell cell2">
      <div class="content section">
        ...
      </div>
    </div>
    <div class="column tableCell cell3">
      <div class="right aside">
        ...
      </div>
    </div>
  </div>
</div>

.table {
  width: auto;
  min-width: 1000px;
  margin: 0 auto;
  padding: 0;
  display: table;
}
.tableRow {
  display: table-row;
}
.tableCell {
  display: table-cell;
  width: 33%;
}
.cell1 {
  background: #f00;
  height: 800px;
}
.cell2 {
  background: #0f0;
}
.cell3 {
  background: #00f;
}

4.使用边框和定位

这种方法是使用边框和绝对定位来实现一个假的高度相等列的效果。结构简单,兼容各浏览器,容易掌握。假设你需要实现一个两列等高布局,侧栏高度要和主内容高度相等。

#wrapper {
  width: 960px;
  margin: 0 auto;
}
#mainContent {
  border-right: 220px solid #dfdfdf;
  position: absolute;
  width: 740px;
  height: 800px;  
  background: green;
}
#sidebar {
  background: #dfdfdf;
  margin-left: 740px;
  position: absolute;
  height: 800px;
  width: 220px;
}

<div id="wrapper">
    <div id="mainContent">...</div>
    <div id="sidebar">...</div>
</div>

五、粘连布局

1.特点

  • 有一块内容<main>,当<main>的高康足够长的时候,紧跟在<main>后面的元素<footer>会跟在<main>元素的后面。
  • <main>元素比较短的时候(比如小于屏幕的高度),我们期望这个<footer>元素能够“粘连”在屏幕的底部

具体代码如下:

    <div id="wrap">
      <div class="main">
        main <br />
        main <br />
        main <br />
      </div>
    </div>
    <div id="footer">footer</div>

* {
    margin: 0;
    padding: 0;
  }
  html,
  body {
    height: 100%;//高度一层层继承下来
  }
  #wrap {
    min-height: 100%;
    background: pink;
    text-align: center;
    overflow: hidden;
  }
  #wrap .main {
    padding-bottom: 50px;
  }
  #footer {
    height: 50px;
    line-height: 50px;
    background: deeppink;
    text-align: center;
    margin-top: -50px;
  }

2.实现步骤

(1)footer必须是一个独立的结构,与wrap没有任何嵌套关系
(2)wrap区域的高度通过设置min-height,变为视口高度
(3)footer要使用margin为负来确定自己的位置
(4)在main区域需要设置 padding-bottom。这也是为了防止负 margin 导致 footer 覆盖任何实际内容。

参考

CSS 常见布局方式
几种常见的CSS布局