圣杯和双飞翼

1,601 阅读3分钟

圣杯布局和双飞翼布局都是实现三栏布局的方法,左右定宽,中间自适应。与普通的三栏布局不同的是,这两种方式将main元素放在侧边栏的前面,以达到优先渲染的目,只是实现的方式略有不同。 下面以一个左边栏100px,右边栏120px的布局来说明。

通用步骤

HTML部分,用一个容器包裹起来,main在left、right前面:

  <div class="container clearfix">
    <div class="main">main</div>
    <div class="left">left</div>
    <div class="right">right</div>
  </div>

初始CSS部分,main、left、right全部左浮,main宽度为100%,清除浮动:

.container {
  border: 1px solid black;
}
/* 清除浮动 */
.clearfix:after {
  content: '';
  display: block;
  clear: both;
}

.main,.left,.right {
  float: left;
}

.main {
  background: #ccc;
  width: 100%;
}

.left {
  background: red;
  width: 100px;
}

.right {
  background: blue;
  width: 120px;
}

此时,main占据一整行,left、right在第二行并排。接下来要将left和right上移,与main同一行。这里使用负margin能够实现。

.left {
  background: red;
  width: 100px;
  margin-left: -100%;/* 值为100%,left会在最左边 */
}

.right {
  background: blue;
  width: 120px;
  margin-left: -120px;/* 值为120px,即right的宽度right会在最右边 */
}

到这一步,三个元素已经并排在一行,但是有一个问题,left、right遮挡了部分main。解决这个问题有两种方法,分别对应圣杯布局和双飞翼布局。

圣杯布局

要解决遮挡,不如先"内部缩窄"container,然后再将left、right“推到合适的地方”。这里要使用相对定位,让left、right脱离文档流。

.container {
  border: 1px solid black;
  padding: 0 120px 0 100px;/*给左右padding,数值为对应左右宽度*/
}
.left {
  background: red;
  width: 100px;
  margin-left: -100%;/* 值为100%,left会在最左边 */
  position: relative;/* 相对定位,左移自身宽度 */
  left: -100px;
}

.right {
  background: blue;
  width: 120px;
  margin-left: -120px;/* 值为120px,即right的宽度right会在最右边 */
  position: relative;
  right: -120px;/* 相对定位,右移自身宽度 */
}

此时可以看到,left、right并没有遮挡住main。这时还需注意,当main宽度小于left宽度时,布局将会打乱。建议给container设置一个min-width值。

效果预览: jsbin.com/gihikon/11/…

双飞翼布局

要解决遮挡,也可以让main给left、right预留位置,“躲开”侧边栏占据的空间。不如给main添加一个容器元素wrap,再设置main的margin值避开侧边栏。 更改后的html:

  <div class="container clearfix">
    <div class="wrap">
      <div class="main">main</div>
    </div>
    <div class="left">left</div>
    <div class="right">right</div>
  </div>
/* 容器左浮 */
.wrap,.left,.right {
  float: left;
}

/* 容器宽度100% */
.wrap {
  background: #ccc;
  width: 100%;
}
/* main左右margin分别为left、right的宽度 */
.main {
  margin-left: 100px;
  margin-right: 120px;
}

.left {
  background: red;
  width: 100px;
  margin-left: -100%;/* 值为100%,left会在最左边 */
}

.right {
  background: blue;
  width: 120px;
  margin-left: -120px;/* 值为120px,即right的宽度right会在最右边 */
}

此时left、right不需要定位,而且main的宽度为0也不会影响到布局,css也更为简单。

效果预览: jsbin.com/fagiyaq/4/e…

额外

都2019年了,还有什么布局是flex不能解决的呢?折腾来折腾去图个啥?

  <div class="container">
    <div class="main">main</div>
    <div class="left">left</div>
    <div class="right">right</div>
  </div>
.container {
  border: 1px solid black;
  display: flex;
}

.main {
  background: #ccc;
  flex: 1;
}

.left {
  background: red;
  width: 100px;
  order: -1;
}

.right {
  background: blue;
  width: 120px;
}