CSS之三栏布局

1,265 阅读5分钟

写在前面

在前端页面制作过程中,三栏布局也是很常见的一种布局方式,三栏布局是主体,通常还包含页眉导航栏和页脚联系信息栏,总共是五大块,大部门网站都是分成这五大栏,页眉导航栏和页脚联系信息栏都是 width: 100%,占满一行,其实 div 等块级元素就默认占满一行。以下介绍中间的三栏布局。

三栏布局的特点是,左边侧边栏和右边侧边栏的宽度是固定的大小的(或者有最大宽度限制的),然后中间一栏的宽度自适应。

1. flex 布局——小case

三栏布局使用 flex 布局则是小case,且两端不用固定宽度和高度,可由内容撑开,以下代码为了不写那么多内容直接用宽度撑开了,其实可以靠内容撑开。

<header>header</header>
<div class="container">
    <aside class="left">left</aside>
    <main>middle</main>
    <aside class="right">right</aside>
</div>
<footer>footer</footer>
body{
  text-align: center;
}
header{
  background: red;
}
footer{
  background: green;
}
.container{
  display: flex;
}
.container aside{
  background: orange;
  height: 100px;
  width: 100px;
}
.container main{
  background: blue;
  flex-grow: 1;
}

2. float布局——有点复杂

以下两种方式是使用 float 布局各种拼凑来回实验总结出来的在早期前端界比较流行的布局方式,听名字不知道其咋起的名字,我觉得一点都不形象,在 flex 布局之前的单靠 float 布局的 css 布局真的需要依靠没有逻辑的东拼西凑,多次实验,然后出来个比较好的办法,总结下来起个名字以便他人使用,下面一步步来吧。

(1) 写html元素标签,页眉 / 主体 / 页脚。中间一栏 main 写在三栏中的最上方

<header>header</header>
<div class="clearfix">
    <main>middle</main>
    <aside class="left">left</aside>
    <aside class="right">right</aside>
</div>
<footer>footer</footer>

(2) 添加基础样式,为了方便将两个侧边栏宽度设置为了一样宽

header{
  background: red;
}
footer{
  background: green;
}
.clearfix main{
  background: blue;
}
.clearfix aside{
  background: orange;
  width: 100px;
}

(3)将三栏元素全部设置为 float: left; 左浮,main自适应主栏的宽度设置为100%,同时其父元素清除浮动

/*---清除浮动---*/
.clearfix{
  zoom: 1;
}
.clearfix:after{
  content: '';
  display: block;
  clear: both;
}
/*---清除浮动---*/

.clearfix main{
  background: blue;
  
  /*add*/
  float: left;
  width: 100%;
}
.clearfix aside{
  background: orange;
  width: 100px;
  
  /*add*/
  float: left;
}

(4) 此时我们需要做的就是让下面的 left 和 right 栏跑上面去,一个跑到 middle 的最左边,一个跑到 middle 的最右边,那么怎么上去呢?使用负margin,并且,让左边元素上去,就设置其左侧margin为 负的middle 栏的宽度,middle 栏的宽度是100%宽,因此设置左栏 margin-left: -100%;,这样左栏就跑到了 middle 的最左边,同理,为了让右边栏跑到 middle 的最右边就需要其左侧跑自身的宽度,即 margin-left: -100px;

/*---巧用负 margin跑上去---*/
.clearfix .left{
  margin-left: -100%;
}
.clearfix .right{
  margin-left: -100px;
}
/*---巧用负 margin跑上去---*/

(5)上述效果看起来是大功告成,但是 main 主栏只是被盖住了,不然你看我的 main 字去哪里了? 因此接下来的操作就是如何将 main 的宽度设置为减去两侧的宽度。此时就分叉形成了两条道路,从而形成了两种不同的叫法,一个叫圣杯布局,一个叫双飞翼布局,如下

2.1 圣杯布局

(6)圣杯布局接下来的做法是为三栏的父元素设置内 padding,左padding为左侧栏的宽度,右padding值为右侧栏的宽度

.clearfix{
  zoom: 1;
  
  /*add*/
  padding: 0 100px 0 100px;
}

(7)此刻左右栏也跟着挤进去了,接下来就是将连个侧边栏再使用相对定位结合负 margin 使其归原位

.clearfix aside{
  background: orange;
  width: 100px;
  float: left;
  
  /*add*/
  position: relative;
}
.clearfix .left{
  margin-left: -100%;
  
  /*add*/
  left: -100px;
}
.clearfix .right{
  margin-left: -100px;
  
  /*add*/
  right: -100px;
}

(8)至此,圣杯布局大功告成,这里我没设置高度,可设置高度进行查看,但三栏的高度必须要设置为一样的值才能使三栏的高度一样,当然不需要一样也可不设置。但是这里存在问题,当缩小到一定程度时布局会乱掉,因此要为body加上 min-width,保持两个固定宽度的侧边栏能显示全。

2.2 双飞翼布局

(6)请自行倒回上述第5步骤,开始另外一个方式的布局,main 内容被覆盖了,除了使用外围的 padding,还可以考虑使用内围的 margin。给main增加一个内层div(. main-inner), 然后设置内围div 的 margin:0 100px 0 100px

<div class="clearfix">

    <!--modify-->
    <main>
      <div class="mainInner">middle</div>
    </main>
    <!--modify-->
    
    <aside class="left">left</aside>
    <aside class="right">right</aside>
  </div>
/*add*/
.clearfix main .mainInner{
  margin: 0 100px 0 100px;
}

(7)得到的效果和上述是一样的,也要记得给body加上min-width,至此,双飞翼版本的三栏布局大功告成

2.3 我的猜想

根据上述第5步骤,我想的是,既然双飞翼布局是使用内围的 margin ,为什么不直接为 main 主栏设置 padding 呢,直接 main{padding: 0 100px 0 100px},这样也能使其内容显示在中间部分,只是其两侧有内容,使用 padding 让其不放内容了,我自己尝试了下也可以,这样就不用圣杯布局那样绕来绕去了,但这样 main 的全部部分并不是看到的部分,我不清楚这样做会有什么问题,肯定有问题,不然就不会有圣杯布局那样绕一大圈了。后续用到再说吧。