以前常听说圣杯布局和双飞翼布局,并没有认真研究过,但实际上,他们只是三栏式布局的两种布局方法而已。本文将介绍三栏式布局的几种思路。
初级方法
页面布局常常要用到左右固定,中间自适应的三栏式布局,以前使用的是下面两种方法:
方法一:左右设置固定宽度,然后使用绝对定位position:absolute及left、right属性定位左右盒子位置,最后根据左右宽度设置中间部分的margin。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| .container { height:200px; overflow:hidden; } .left { width: 200px; height: 200px; position: absolute; left: 0; top: 40px; background-color: #E79F6D; } .middle { height: 200px; margin: 0 210px 0 200px; background-color: #D6D6D6;
.right { width: 210px; height: 200px; position: absolute; right: 0; top: 40px; background-color: #77BBDD; }
|
方法二:左右设置固定宽度,分别左右浮动;根据左右宽设置中间部分的margin;设置父元素overflow:hidden;注意采用这种方法时,html布局上中间部分必须放在最后,即左右中的顺序,这是因为中间不是浮动的,需要单独占行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| .container { height:200px; overflow:hidden; } .left { width: 200px; height: 200px; float: left; background-color: #E79F6D; } .right { width: 210px; height: 200px; float: right; background-color: #77BBDD; } .middle { height: 200px; margin: 0 210px 0 200px; background-color: #D6D6D6; }
|
但是,实际产品中往往需要中间部分最先渲染,也就是“重要的内容先加载”,这种结构会更好一些,所以我们需要中左右的布局顺序,这种情况有两种经典的实现方式:圣杯布局和双飞翼布局。
圣杯布局
下面我们按照常规思路来一步步实现圣杯布局:
原始布局
HTML结构:
1 2 3 4 5 6 7
| <header>Header</header> <div class="container"> <div class="middle">中间弹性区</div> <div class="left">左边栏</div> <div class="right">右边栏</div> </div> <footer>Footer</footer>
|
每个盒子的样式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| header { width: 100%; height: 40px; background-color: #aaa; } .container { overflow:hidden; } .middle { width: 100%; height: 200px; float:left; background-color: #D6D6D6; } .left { width: 200px; height: 200px; float:left; background-color: #E79F6D; } .right { width: 210px; height: 200px; float:left; background-color: #77BBDD; } footer { width: 100%; height: 30px; clear: both; background-color: #666; }
|
问题:此时三栏并没有在父元素的一行显示,因为中间盒子我们给了百分之百的宽度,所以左右两个盒会被挤下来。
这时需要让左右两边的盒子上去,可以通过负边距实现。
设置左边盒子的左边距为负的container的宽度,即.left {margin-left:-100%;}
。
设置右边的盒子其左边距为负的自己的宽度,也就是.right {margin-left:-200px;}
。
问题:此时中间盒子里的内容会被左右盒子给压住一部分。
利用父级元素设置左右内边距的值,把父级的盒子往中间挤。.container{ padding: 0 200px 0 200px;}
。
问题:左右盒子都随中间盒子往中间挤了,需要将左右的恢复到原来的位置。
给左右两个盒子加相对定位,左右两个盒子就可以设置left和right值。.left{ position: relative; left: -200px;}
,.right{position: relative;right: -210px;}
。至此,圣杯布局完成。
缺点:并没有实现等高布局;使用了相对定位,扩展性不好。
完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| <!DOCTYPE html> <html> <head> <title></title> <style type="text/css"> header { width: 100%; height: 40px; background-color: #aaa; } .container { height:200px; padding: 0 210px 0 200px; overflow:hidden; } .middle { width: 100%; height: 200px; float:left; background-color: #D6D6D6; } .left { width: 200px; height: 200px; margin-left:-100%; float:left; position: relative; left: -200px; background-color: #E79F6D; } .right { width: 210px; height: 200px; margin-left: -210px; float:left; position: relative; right: -210px; background-color: #77BBDD; } footer { width: 100%; height: 30px; background-color: #666; } </style> </head> <body> <header>Header</header> <div class="container"> <div class="middle">中间弹性区</div> <div class="left">左边栏</div> <div class="right">右边栏</div> </div> <footer>Footer</footer> </body> </html>
|
双飞翼布局
双飞翼布局可以看成是对圣杯布局的改进。前两步都是一样的,重要的是第三步,在前两步的完成后已经形成同行排列,只不过中间栏里面的内容被遮挡。为解决这个问题,圣杯布局的第三步是给container容器添加padding属性,而双飞翼布局是为main里面的内容再加一个div,让main的内容包含在内层div里,设置内层div的margin-left和margin-right为左右两栏div留出位置。
优点:比圣杯布局少用了多个属性,更直接和简洁。
缺点:并没有实现等高布局,增加了html结构。
1 2 3 4 5 6 7 8 9
| <header>Header</header> <div class="container"> <div class="middle"> <div class="middle-inner">中间弹性区</div> </div> <div class="left">左边栏</div> <div class="right">右边栏</div> </div> <footer>Footer</footer>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| header { width: 100%; height: 40px; background-color: #aaa; } .container { height:200px; overflow:hidden; } .middle { width: 100%; height: 200px; float:left; background-color: #D6D6D6; } .left { width: 200px; height: 200px; margin-left:-100%; float:left; background-color: #E79F6D; } .right { width: 210px; height: 200px; margin-left: -210px; float:left; background-color: #77BBDD; } .middle-inner { margin: 0 210px 0 200px; } footer { width: 100%; height: 30px; clear: both; background-color: #666; }
|
绝对定位
设置子元素的top:0;bottom:0;使得所有子元素的高度都和父元素的高度相同,实现等高效果。
缺点: 需要为容器元素设置高度,扩展性较差。
1 2 3 4 5 6 7
| <header>Header</header> <div class="container"> <div class="middle">中间弹性区</div> <div class="left">左边栏</div> <div class="right">右边栏</div> </div> <footer>Footer</footer>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| header { width: 100%; height: 40px; background-color: #aaa; } .container { height: 200px; position: relative; } .middle, .left, .right { position: absolute; top: 0; bottom: 0; } .middle { left: 200px; right: 210px; background-color: #D6D6D6; } .left { width: 200px; background-color: #E79F6D; } .right { width: 210px; right: 0; background-color: #77BBDD; } footer { width: 100%; height: 30px; background-color: #666; }
|
flex布局
flex中的伸缩项目默认都拉伸为父元素的高度,可实现等高效果。通过改变伸缩项目的order,可以实现元素顺序调换的效果。
设置中间盒子flex: 1可实现伸缩。flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。如果所有项目的flex-grow属性都为1,则它们将等分剩余空间。
缺点: 兼容性不高。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| header { width: 100%; height: 40px; background-color: #aaa; } .container { display: flex; } .middle { order: 1; flex: 1; height: 200px; background-color: #D6D6D6; } .left { width: 200px; height: 200px; background-color: #E79F6D; } .right { order: 2; width: 210px; height: 200px; background-color: #77BBDD; } footer { width: 100%; height: 30px; background-color: #666; }
|
总结
各种方法各有优缺点,个人更倾向于使用强大简洁的flex布局,让古董浏览器见鬼去吧。
后记
最近在找一些小项目练手,在github上看到很多如我一样的初学者,他们将做项目中遇到的每个问题,无论大小,分析根源,记录在博客中,他们认真细致的态度真让我自愧不如,甚至惊叹。现在他们很多是BAT的员工了,我想这是助他们进入大公司的重要特质之一。像我就是很多时候遇到问题,没有及时记录,或者问题没有分析透彻,似懂非懂,结果下次遇到还是不会。深入思考,弄清每一处细节,比似懂非懂多学几个知识点要重要得多。
参考
圣杯布局和双飞翼布局-简书
三栏式布局(所谓的圣杯和双飞翼)-博客园