一、CSS包含3种基本的布局模型,用英文概括为:Flow、Layer 和 Float。
在网页中,元素有三种布局模型:1、流动模型(Flow)-
流动模型是默认的网页布局模式。
-
在流动模型下,内联元素都会在所处的包含元素内从左到右按顺序水平分布显示。
- 在流动模型下,块状元素都会在所处的包含元素内自上而下按顺序垂直延伸分布,在默认状态下,块状元素的宽度都为100%。
2、浮动模型 (Float)
float:right/left/none;
- 任何元素在默认情况下是不能浮动的,但可以用 CSS 定义为浮动
3、层模型(layer)
绝对定位position: absolute; 相对定位position: relative; 固定定位position: fixed;
- 对每个图层能够精确定位操作
解释
- absolute:如果想为元素设置层模型中的绝对定位,需要设置position:absolute(表示绝对定位),这条语句的作用将元素从文档流中拖出来,然后使用left、right、top、bottom属性相对于其最接近的一个具有定位属性的父包含块进行绝对定位。如果不存在这样的包含块,则相对于body元素,即相对于浏览器窗口。
- relative:如果想为元素设置层模型中的相对定位,需要设置position:relative(表示相对定位),它通过left、right、top、bottom属性确定元素在正常文档流中的偏移位置。相对定位完成的过程是首先按static(float)方式生成一个元素(并且元素像层一样浮动了起来),然后相对于以前的位置移动,移动的方向和幅度由left、right、top、bottom属性确定,偏移前的位置保留不动。
- fixed:表示固定定位,与absolute定位类型类似,但它的相对移动的坐标是视图(屏幕内的网页窗口)本身。由于视图本身是固定的,它不会随浏览器窗口的滚动条滚动而变化,除非你在屏幕中移动浏览器窗口的屏幕位置,或改变浏览器窗口的显示大小,因此固定定位的元素会始终位于浏览器窗口内视图的某个位置,不会受文档流动影响,这与background-attachment:fixed;属性功能相同。
圣杯布局与双飞翼布局针对的都是三列左右栏固定中间栏边框自适应的网页布局(想象一下圣杯是主体是加上两个耳朵;鸟儿是身体加上一对翅膀),圣杯布局是Kevin Cornell在2006年提出的一个布局模型概念,在国内最早是由淘宝UED的工程师(传说是玉伯)改进并传播开来,在中国也有叫法是双飞翼布局,它的布局要求有几点:
-
三列布局,中间宽度自适应,两边定宽;
-
中间栏要在浏览器中优先展示渲染;
-
允许任意列的高度最高;
下面我们看看具体的实现方法。
一、圣杯布局
HTML结构
1 2 3 4 5 6 7 | < div class = "header" >header</ div > < div class = "container" > < div class = "main" >main</ div > < div class = "left" >left</ div > < div class = "right" >right</ div > </ div > < div class = "footer" >footer</ div > |
因为需要中间栏优先展示渲染,所以中间的main在HTML的结构中却是最靠前的。在实际的网站中这样做的好处就是用户能够先看到网页正文信息,一般网页两边的导航信息和说明信息我们认为优先级没有正文重要。
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 | *{ margin : 0 ; padding : 0 ;} body{ min-width : 700px ;} .header,.footer{ border : 1px solid #333 ; background : #aaa ; text-align : center ; } . left ,.main,. right { min-height : 130px ; } .container{ border : 2px solid yellow; } . left { width : 200px ; background : red ; } . right { width : 220px ; background : green ; } .main{ background : blue ; } |
为了高度保持一致给left middle right都加上min-height:130px
2.将主体部分的三个子元素都设置左浮动
1 2 3 | . left ,.main,. right { float : left ; } |
此时的页面显示如图所示,Shen Me Gui没关系,事情会变得好起来的
我们看一下上面的效果比较明显的两个问题,一是footer跑到上面去了,二是container容器高度塌陷了,这是典型的“清除浮动和闭合浮动”问题。
3.解决浮动问题
1 2 3 4 5 6 7 | .container{ border : 2px solid yellow; overflow : hidden ; /*闭合浮动*/ } .footer{ clear : both ; /*清楚浮动*/ } [附]清浮动常用的方法 .clearfix:after{ content:""; display:block; clear:both } .clearfix{ *zoom:1; /*解决兼容性问题*/ } |
给container加上overflow:hidden触发BFC闭合浮动,给footer加上clear属性清除浮动。
我们发现footer移到了下面,并且container的高度塌陷也修复了。
4.设置main宽度为width:100%,让其单独占满一行
1 2 3 4 | .main{ width : 100% ; background : blue ; } |
5.设置left和right负的外边距
我们的目标是让left、main、right依次并排,但是上图中left和right都是位于下一行,这里的技巧就是使用负的margin-left:
1 2 3 4 5 6 7 8 9 10 | . left { margin-left : -100% ; width : 200px ; background : red ; } . right { margin-left : -220px ; width : 220px ; background : green ; } |
负的margin-left会让元素沿文档流向左移动,如果负的数值比较大就会一直移动到上一行。关于负的margin的应用也是博大精深,这里肯定是不能详细介绍了。
设置left部分的margin-left为-100%,就会使left向左移动一整个行的宽度,由于left左边是父元素的边框,所以left继续跳到上一行左移,一直移动到上一行的开头,并覆盖了main部分(仔细观察下图,你会发现main里面的字“main”不见了,因为被left遮住了),left上移过后,right就会处于上一行的开头位置,这是再设置right部分margin-left为负的宽度,right就会左移到上一行的末尾。6.修复覆盖问题
第五步我们说过设置left和right负的外边距覆盖了main部分的内容,现在想办法修复这个问题,首先给container的左右加上一个内边距,分别为left和right的宽度。
1 2 3 4 5 | .container{ border : 2px solid yellow; padding : 0 220px 0 200px ; overflow : hidden ; } |
由于left、main、right三个部分都被container包裹着,所以给其添加内边距,三个子元素会往中间挤。貌似还是没有修复问题,别着急,我们已经在container的左右两边留下了相应宽度的留白,只要把left和right分别移动到这两个留白就可以了。可以使用相对定位移动left和right部分,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | . left ,.main,. right { position : relative ; float : left ; min-height : 130px ; } . left { margin-left : -100% ; left : -200px ; width : 200px ; background : red ; } . right { margin-left : -220px ; right : -220px ; width : 220px ; background : green ; } |
至此,我们完成了三列中间自适应的布局,也就是传说中的圣杯布局。完整的代码如下:
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 57 | <!DOCTYPE html> < html > < head > < meta charset = "utf-8" > < title >圣杯布局</ title > < style type = "text/css" > *{margin: 0;padding: 0;} body{min-width: 700px;} .header, .footer{ border: 1px solid #333; background: #aaa; text-align: center; } .left, .main, .right{ position: relative; float: left; min-height: 130px; } .container{ border: 2px solid yellow; padding:0 220px 0 200px; overflow: hidden; } .left{ margin-left: -100%; left: -200px; width: 200px; background: red; } .right{ margin-left: -220px; right: -220px; width: 220px; background: green; } .main{ width: 100%; background: blue; } .footer{ clear: both; } </ style > </ head > < body > < div class = "header" >header</ div > < div class = "container" > < div class = "main" >main</ div > < div class = "left" >left</ div > < div class = "right" >right</ div > </ div > < div class = "footer" >footer</ div > </ body > </ html > |
二、双飞翼布局
圣杯布局和双飞翼布局解决问题的方案在前一半是相同的,也就是三栏全部float浮动,但左右两栏加上负margin让其跟中间栏div并排,以形成三栏布局。不同在于解决”中间栏div内容不被遮挡“问题的思路不一样。
HTML 结构
1 2 3 4 5 6 7 8 9 | < div class = "header" >header</ div > < div class = "container" > < div class = "main" > < div class = "content" >main</ div > </ div > < div class = "left" >left</ div > < div class = "right" >right</ div > </ div > < div class = "footer" >footer</ div > |
双飞翼布局的前五步和圣杯布局完全相同,我们只需要修改第六步,前面是设置container的内边距以及相对定位来解决这个覆盖问题的,双飞翼布局中,为了main内容不被遮挡,在main里面添加一个子元素content来显示内容,然后设置content的margin-left和margin-right为左右两栏div留出位置。
直接贴出代码,读者可以自行参透他们的异同:
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 57 58 | <!DOCTYPE html> < html > < head > < meta charset = "utf-8" > < title >圣杯布局</ title > < style type = "text/css" > *{margin: 0;padding: 0;} body{min-width: 700px;} .header, .footer{ border: 1px solid #333; background: #aaa; text-align: center; } .left, .main, .right{ float: left; min-height: 130px; } .container{ border: 2px solid yellow; overflow: hidden; } .left{ margin-left: -100%; width: 200px; background: red; } .right{ margin-left: -220px; width: 220px; background: green; } .main{ width: 100%; background: blue; } .content{ margin: 0 220px 0 200px; } .footer{ clear: both; } </ style > </ head > < body > < div class = "header" >header</ div > < div class = "container" > < div class = "main" > < div class = "content" >main</ div > </ div > < div class = "left" >left</ div > < div class = "right" >right</ div > </ div > < div class = "footer" >footer</ div > </ body > </ html > |
双飞翼布局比圣杯布局多使用了1个div,少用大致4个css属性(圣杯布局container的 padding-left和padding-right这2个属性,加上左右两个div用相对布局position: relative及对应的right和left共4个属性,;而双飞翼布局子div里用margin-left和margin-right共2个属性,比圣杯布局思路更直接和简洁一点。简单说起来就是”双飞翼布局比圣杯布局多创建了一个div,但不用相对布局了。