在看众多大神的css布局指南时,经常看到一个布局:圣杯布局(也有称为双飞翼布局的)。今天我们也来剖析一下。
其实,对于众多css布局,我们只要明确理解了3种技术,那么基本上大多数布局都难不倒我们了:
浮动 float
绝对定位和相对定位 negative margin
负边距 relative position
浮动
浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止。
由于浮动框不在文档的普通流中,所以文档的普通流中的块框表现得就像浮动框不存在一样。(w3c)
上面是官方的界定。我们可以用"float:left"和"float:right"来使元素块向左向右浮动。
当一个元素块被浮动后,其在原文档流中的空间被关闭,后面的内容会向前补充,这样很容易造成后面的元素包围了浮动的元素块。
为了解决这个问题,我们可以用clear方法来阻止行框包围元素块。
绝对定位和相对定位
我们通过position属性来声明这个元素块进行绝对定位或者相对定位。如果要进行定位的是行内元素,首先需要用display:block来将其声明为一个块级元素。
两者的区别为:
相对定位是相对于自身在文档流中的原有位置的起点为基准进行位移定位。其在文档流中的位置不会被关闭。
绝对定位是相对于最接近的已定位父元素的起点为基准,如果没有已定位的父元素,则为其最初的包含快,也就是body。绝对定位相对于相对定位的不同,是其在文档流中的元素框被关闭,该位置被后面的元素填充。
负边距
在css中,有两种边距,分别为内边距padding和外边距margin。
内边距padding是元素内动与边框之间的距离,外边距margin为元素边框到父元素框外边距之间的距离。
内边距padding只能设置为正值,而外边距margin可以设置为正值也可以设置为负值。
我们还需要了解一点,元素的背景是可以占用内边距padding距离的。
了解了以上三种方法,我们就可以通过这三种方法来实现我们的各种布局。
这包括了下面介绍的圣杯布局:
先写一个基本布局:
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 2 <html> 3 <head> 4 <meta http-equiv="content-type" content="text/html; charset=utf-8" /> 5 <title>圣杯布局/双飞翼布局</title> 6 <style type="text/css"> 7 * { 8 margin: 0; 9 padding: 0; 10 text-Align: center; 11 } 12 #parents { 13 width: 600px; 14 border: 2px solid; 15 margin: 0 auto; 16 } 17 #top { 18 background: #666; 19 } 20 #left { 21 background: #E79F6D; 22 } 23 #content { 24 background: #D6D6D6; 25 } 26 #right { 27 background: #77BBDD; 28 } 29 #foot { 30 background: #666; 31 } 32 </style> 33 </head> 34 <body> 35 <div id="parents"> 36 <div id="top">这是Top!</div> 37 <div id="main"> 38 <div id="left">这是Left!</div> 39 <div id="content">这是Content!</div> 40 <div id="right">这是Right!</div> 41 </div> 42 <div id="foot">这是Foot!</div> 43 </div> 44 </body> 45 </html>
效果:
我们将中间left、content和right向左浮动,并设置left和right的宽度分别设置为100px和150px,将三者的父元素的左右内边距设置为100px和150px,与left和right的宽度相同。然后我们将foot清除浮动。
1 <style type="text/css"> 2 * { 3 margin: 0; 4 padding: 0; 5 text-Align: center; 6 } 7 #parents { 8 width: 600px; 9 border: 2px solid; 10 margin: 0 auto; 11 } 12 #top { 13 background: #666; 14 } 15 #main { 16 margin-left: 100px; 17 margin-right: 150px; 18 } 19 #left { 20 background: #E79F6D; 21 float: left; 22 width: 100px; 23 } 24 #content { 25 background: #D6D6D6; 26 float: left; 27 width: 100%; 28 } 29 #right { 30 background: #77BBDD; 31 float: left; 32 width: 150px; 33 } 34 #foot { 35 background: #666; 36 clear: both; 37 } 38 </style>
效果:
我们发现,由于content宽度设置了100%,故而其宽度不够,所以content和right就掉下来了,对于这个我们可以为content和right设置一个margin-left属性来解决这个问题。
1 #left { 2 background: #E79F6D; 3 float: left; 4 width: 100px; 5 } 6 #content { 7 background: #D6D6D6; 8 float: left; 9 width: 100%; 10 margin-left: -100px; 11 } 12 #right { 13 background: #77BBDD; 14 float: left; 15 width: 150px; 16 margin-left: -150px; 17 }
效果:
上图中left被content挡住了。
随后,我们用相对定位把left向左移,right向右移。并把top和foot设置高度为50px;
1 #top { 2 background: #666; 3 height: 50px; 4 } 5 #main { 6 padding-left: 100px; 7 padding-right: 150px; 8 } 9 #left { 10 background: #E79F6D; 11 float: left; 12 width: 100px; 13 position: relative; 14 left: -100px; 15 } 16 #content { 17 background: #D6D6D6; 18 float: left; 19 width: 100%; 20 margin-left: -100px; 21 } 22 #right { 23 background: #77BBDD; 24 float: left; 25 width: 150px; 26 margin-left: -150px; 27 position: relative; 28 left: 150px; 29 } 30 #foot { 31 background: #666; 32 clear: both; 33 height: 50px; 34 }
效果:
看起来差不多了,不过我们还需要处理一个问题,就是中间三列的等高问题,这个是在前面已经探讨过的多列等高问题。
1 <style type="text/css"> 2 * { 3 margin: 0; 4 padding: 0; 5 text-Align: center; 6 } 7 #parents { 8 width: 600px; 9 border: 2px solid; 10 margin: 0 auto; 11 } 12 #top { 13 background: #666; 14 height: 50px; 15 } 16 #main { 17 padding-left: 100px; 18 padding-right: 150px; 19 overflow: hidden; 20 } 21 #left,#content,#right { 22 padding-bottom: 2000px; 23 margin-bottom: -2000px; 24 } 25 #left { 26 background: #E79F6D; 27 float: left; 28 width: 100px; 29 position: relative; 30 left: -100px; 31 } 32 #content { 33 background: #D6D6D6; 34 float: left; 35 width: 100%; 36 margin-left: -100px; 37 } 38 #right { 39 background: #77BBDD; 40 float: left; 41 width: 150px; 42 margin-left: -150px; 43 position: relative; 44 left: 150px; 45 } 46 #foot { 47 background: #666; 48 clear: both; 49 height: 50px; 50 } 51 </style>
效果:
这样就没问题了,当我们给三者无论哪个添加内容时,三列的高度总会以最高的那列为准维持等高。
在这个布局中,主要内容content的宽度是自适应的,而left和right的宽度是固定的,当我们增加parents的宽度时,content的宽度随之增加,left和right保持不变。
这就是圣杯布局,也有叫做双飞翼布局的。
而且我们通过相对定位,可以通过计算,随意定制left、content和right三者的前后顺序。
关于圣杯布局,引用一下CobbySung总结的优缺点:
优点:
- 实现了内容与布局的分离,即Eric提到的Any-Order Columns.
- content部分是自适应宽度的,很容易在定宽布局和流体布局中切换。
- 任何一栏都可以是最高栏,不会出问题。
- 需要的hack非常少(就一个针对ie6的清除浮动hack:_zoom: 1;)
- 在浏览器上的兼容性非常好,IE5.5以上都支持。
不足:
- content需要添加一个额外的包裹层。
- 等待你的发现与反馈。
最后附上完整代码:
1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 2 <html> 3 <head> 4 <meta http-equiv="content-type" content="text/html; charset=utf-8" /> 5 <title>圣杯布局/双飞翼布局</title> 6 <style type="text/css"> 7 * { 8 margin: 0; 9 padding: 0; 10 text-Align: center; 11 } 12 #parents { 13 width: 1000px; 14 border: 2px solid; 15 margin: 0 auto; 16 } 17 #top { 18 background: #666; 19 height: 50px; 20 } 21 #main { 22 padding-left: 100px; 23 padding-right: 150px; 24 overflow: hidden; 25 } 26 #left,#content,#right { 27 padding-bottom: 2000px; 28 margin-bottom: -2000px; 29 } 30 #left { 31 background: #E79F6D; 32 float: left; 33 width: 100px; 34 position: relative; 35 right: 150px; 36 left: 100px; 37 38 } 39 #content { 40 background: #D6D6D6; 41 float: left; 42 width: 100%; 43 margin-left: -100px; 44 position: relative; 45 left: -100px; 46 } 47 #right { 48 background: #77BBDD; 49 float: left; 50 width: 150px; 51 margin-left: -150px; 52 position: relative; 53 left: 150px; 54 } 55 #foot { 56 background: #666; 57 clear: both; 58 height: 50px; 59 } 60 </style> 61 </head> 62 <body> 63 <div id="parents"> 64 <div id="top">这是Top!</div> 65 <div id="main"> 66 <div id="left">这是Left!</div> 67 <div id="content">这是Content!<br><br><br><br>这是多行高度!<br></div> 68 <div id="right">这是Right!</div> 69 </div> 70 <div id="foot">这是Foot!</div> 71 </div> 72 </body> 73 </html>