圣杯布局和双飞翼布局实现两侧宽度固定,中间宽度自适应及其他扩展实现


前沿简介

圣杯布局和双飞翼布局是前端重要的布局方式。两者的功能相同,都是为了实现一个两侧宽度固定,中间宽度自适应的三栏布局

圣杯布局来源于文章In Search of the Holy Grail,双飞翼布局来源于淘宝UED。

两者的实现方式有差异,但是都遵循以下几点:

  • 两侧宽度固定,中间宽度自适应
  • 中间部分在DOM结构上优先,以便先行渲染
  • 允许三列中的任意一列称为最高列
  • 只需要使用一个额外的
    标签

圣杯布局

DOM结构


主体由container包裹center、left、right三部分,其中的center在最前面,优先渲染。

CSS代码

假设左侧固定宽度200px,右侧固定宽度150px,在container上设置如下样式:

#container {
	padding-left: 200px;
	padding-right: 150px;
}

目的就是给左侧以及右侧预留出空间,得到如下示意图:

随后为左中右三列设置浮动与对应的宽度,同时为底部footer设置清除浮动。

#container .column {
  float: left;
}

#center {
  width: 100%;
}

#left {
  width: 200px; 
}

#right {
  width: 150px; 
}

#footer {
  clear: both;
}

得到如下示意图效果:

由于center设置了宽度100%,所有左侧left跟右侧right被挤到了第二行。

如果要把left放到预留的位置,那么需要使用负外边距,代码如下:

#left {
  width: 200px; 
  margin-left: -100%;
}

得到如下示意图效果:

由于margin-right: -100%占据叠到了center列左侧,那么需要用定位并且设置right的值为left列的宽度才能放到左侧预留的位置,代码如下:

#left {
	width: 200px;
	margin-left: -100%;
	position:relative;
	right: 200px;
}

这样后得到的示意图效果:

接下来对right列进行设置,代码如下:

#right {
	width: 150px;
	margin-right: -150px;
}

最终的示意图效果:

到这儿页面的基本样式完成。但是我们需要考虑页面的最小宽度,由于两侧有个固定宽度,感觉最小宽度就是200+150=350px,但是由于left列使用了定位position:relative,所以center列至少有个left设置的right值的宽度,即200px,所以最终的最小宽度是:200+150+200=550px。

body {
  min-width: 550px;
}

那么圣杯布局的整体CSS代码如下:

body {
  min-width: 550px;
}

#container {
  padding-left: 200px; 
  padding-right: 150px;
}

#container .column {
  float: left;
}

#center {
  width: 100%;
}

#left {
  width: 200px; 
  margin-left: -100%;
  position: relative;
  right: 200px;
}

#right {
  width: 150px; 
  margin-right: -150px; 
}

#footer {
  clear: both;
}

为了看到效果,贴一个完整示例代码,有模块的背景色:





圣杯布局




中间内容
左侧内容

双飞翼布局

DOM结构


双飞翼布局的DOM结构与圣杯布局的区别是用container仅包裹住center,另外将.column类从center移至container上。

CSS代码

跟前面思路一样,设置各列宽度与浮动,为左右两列预留出空间,以及底部footer清除浮动,代码如下:

#container {
  width: 100%;
}

.column {
  float: left;
}

#center {
  margin-left: 200px;
  margin-right: 150px;
}

#left {
  width: 200px; 
}

#right {
  width: 150px; 
}

#footer {
  clear: both;
}

left放到预留位置左侧:

#left {
  width: 200px; 
  margin-left: -100%;
}

right放到预留位置右侧:

#right {
  width: 150px; 
  margin-left: -150px;
}

最终计算页面的最小宽度:200+150=350px;虽然左侧没有用到定位,但是如果页面的宽度小于350px,那么会挤占中间center的宽度,故设置页面最小宽度为500px,代码如下:

body {
  min-width: 500px;
}

双飞翼布局的完整CSS代码:

body {
  min-width: 500px;
}

#container {
  width: 100%;
}

.column {
  float: left;
}
        
#center {
  margin-left: 200px;
  margin-right: 150px;
}
        
#left {
  width: 200px; 
  margin-left: -100%;
}
        
#right {
  width: 150px; 
  margin-left: -150px;
}
        
#footer {
  clear: both;
}

为了看到效果,也贴一个完整示例代码,有模块的背景色:




	
	双飞翼布局




中间内容
左侧内容

扩展实现

如果去掉额外添加的

标签,也能实现相同的布局。

DOM结构变化为如下:


基于双飞翼布局的实现思路,只需要在center上做出修改。

1.使用calc()

.column {
  float: left;
}
#center {
  margin-left: 200px;
  margin-right: 150px;
  width: calc(100% - 350px);
}
#left{
	width: 200px;
	margin-left: -100%;
}
#right {
	width: 150px;
	margin-left: -150px;
}
#footer {
	clear: both;
}

2.使用border-box

.column {
  float: left;
}

#center {
  padding-left: 200px;
  padding-right: 150px;
  box-sizing: border-box;
  width: 100%;
}

需要注意的是:由于padding是盒子的一部分,所以padding部分会具有中间栏的背景色,当中间栏高于侧栏时,会出现中间背景色出现在侧栏下面中。

3.使用flex

DOM结构如下:


CSS代码:

#container {
	display: flex;
}
#center {
	flex: 1;
}
#left {
	flex: 0 0 200px;
	order: -1;
}
#right {
	flex: 0 0 150px;
}

参考地址:

  • 《圣杯布局和双飞翼布局的理解与思考》