CSS中常用的页面布局:两栏布局、三栏布局
注意:只要用到了浮动,都要考虑要让父元素包含它
1. 两栏布局
1.1 两栏固定布局
width+left
width+right
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
* {margin:0;padding:0;}
#wrapper{
width:800px;
background-color: yellow;
overflow: hidden;/*包含浮动子元素*/
}
.left {
width:200px;
height:200px;
background-color: rgba(0,0,255,0.3);
float: left;
}
.right {
width:400px;
height:300px;
background-color: rgba(0,0,255,0.3);
float: right;
}
</style>
</head>
<body>
<div id="wrapper">
<div class="left">
<p>
这是<em>左栏</em>哦!
width:200px;
height:200px;
</p>
</div>
<div class="right">
<p>
这是<em>右栏</em>哦!
width:300px;
height:400px;
</p>
</div>
</div>
</body>
</html>
1.2 左侧宽度固定、右侧宽度自适应
1.2.1 左侧浮动+右侧margin-left/padding-left隔开
DOM结构中左栏在上方
左栏:固定width+float:left
右栏:padding-left/margin-left
原理:不设置width、height的普通block元素,水平方向的margin能够修改border box的水平尺寸。
不设置width、height的普通block元素,水平方向的padding能够修改content box的水平尺寸。
间隔:如果想让左、右栏之间有间隔,比如30px,可以增大当前使用的padding-left为width+间隔,或者margin-left为width+间隔,或者在当前使用的padding-left或者margin-left的基础上增加margin-left:30px;或者padding-left:30px;
(1)用margin-left实现
这种实现方法中,整个border box从div.left的右侧紧贴着放置。
HTML结构
<div id="wrapper">
<div class="left">
<p>
这是左栏哦!
</p>
</div>
<div class="right">
<img src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2096432854,4113309096&fm=26&gp=0.jpg"
width="150" height="150" alt="Some of a team">
</div>
</div>
CSS代码
#wrapper{
width:500px;
background-color: yellow;
overflow: hidden;/*包含浮动子元素*/
resize:both;
}
.left {
width:200px;
height:200px;
background-color:green;
float: left;
}
.right {
background-color: blue;
margin-left: 200px;
}
如果想让左右栏右一定的间隔,可以在原本代码的基础上,在div.right中添加padding-left。或者把margin-left的值增大相应的值也行,比如margin-left:230px;
margin-left:230px;
margin-left:200px; + padding-left:30px;的效果:
(2)用padding-left实现
仅将1.2.1中的margin-left:200px;换成padding-left:200px;这种实现方法中,整个border box依然从包含块的左上角放置。
如果想让左右栏有一定的间距,可以通过padding-left:200px;+margin-left:30px;实现,或者通过padding-left:230px;实现。
1.2.2 左侧浮动+右侧BFC
DOM结构不变,CSS代码:如需左右的间隔,可在left中加margin或者padding
#wrapper{
width:500px;
background-color: yellow;
overflow: hidden;/*包含浮动子元素*/
resize:both;
}
.left {
width:200px;
height:200px;
background-color:green;
float: left;
}
.right {
background-color: blue;
overflow:hidden;/*右侧BFC*/
}
1.3 右侧宽度固定、左侧宽度自适应
1.3.1 DOM结构right栏在上方
DOM结构中右栏在上方
右栏:固定width+float:right
左栏:padding-right/margin-right
原理:不设置width、height的普通block元素,水平方向的margin能够修改border box的水平尺寸。
不设置width、height的普通block元素,水平方向的padding能够修改content box的水平尺寸。
间隔:如果想让左、右栏之间有间隔,比如30px,可以增大当前使用的padding-right为width+间隔,或者margin-right为width+间隔,或者在当前使用的padding-right或者margin-right的基础上增加margin-right:30px;或者padding-right:30px;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>两栏自适应布局:右侧固定,左侧自适应</title>
<style type="text/css">
* {margin:0;padding:0;}
#wrapper{
width:500px;
background-color: yellow;
overflow: hidden;/*包含浮动子元素*/
resize:both;
}
.left {
background-color: green;
margin-right: 150px;
}
.right {
float: right;
width:150px;
height:150px;
background-color: blue;
}
</style>
</head>
<body>
<div id="wrapper">
<div class="right">
<img src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2096432854,4113309096&fm=26&gp=0.jpg"
width="150" height="150" alt="Some of a team">
</div>
<div class="left">
<p>
这是左栏哦!这是左栏哦!这是左栏哦!这是左栏哦!这是左栏哦!
</p>
</div>
</div>
</body>
</html>
1.3.2 DOM结构right栏在下方
DOM结构:right在下方
写法:
- left外面加上一层div标签,父标签float:left,并且宽度100%
- 原始left设置margin-right为right栏的宽度
- right栏float:left,margin-left为自身宽度的负值
注意:由于二者都浮动了,需要让父元素包含浮动的子元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>两栏自适应布局:右侧固定,左侧自适应</title>
<style type="text/css">
* {margin:0;padding:0;}
#wrapper{
width:500px;
background-color: yellow;
overflow: hidden;/*包含浮动子元素*/
resize:both;
}
.outerDiv {
width:100%;
float: left;
}
.left {
background-color: green;
margin-right: 150px;/*防止wrapper较小时右栏遮挡左栏内容*/
}
.right {
float: left;
width:150px;
height:150px;
background-color: blue;
margin-left: -150px;/*将右栏向左拉*/
}
</style>
</head>
<body>
<div id="wrapper">
<div class="outerDiv">
<div class="left">
这是左栏哦!这是左栏哦!这是左栏哦!这是左栏哦!这是左栏哦!
</div>
</div>
<div class="right">
<img src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2096432854,4113309096&fm=26&gp=0.jpg"
width="150" height="150" alt="Some of a team">
</div>
</div>
</body>
</html>
1.4 左右两侧都自适应(不理解?)
左侧固定时,改变容器,右侧自适应;左侧改变且容器不变时,右侧自适应改变。
思路:只将左侧元素浮动,另一侧元素采用display:table-cell(IE8+)或者display:inline-block(IE7)而实现跟随的效果。
总结:
元素1:float:left(不设置width)
元素2:display:table-cell(IE8+)或者display:inline-block(IE7)
兼容IE浏览器的CSS属性写法:在属性前面添加*,例如
自适应宽度的一般不设置width。
2.三栏布局
三栏布局一般指的是左、右宽度固定,中间宽度自适应的布局
2.1 简单的浮动布局
DOM结构:left、right、middle,即middle最后渲染
写法:left:width+左浮动,right:width+右浮动,middle:不设置width,margin-left=左宽度,margin-right=右宽度
思路:利用了没有设置width的普通block元素,通过设置水平margin能够修改border box尺寸的特性
注意:让父元素包含浮动子元素,但是此处不加父元素也不会高度塌陷,因为middle是普通元素,但是还是加上最好。
类比:这个思路相当于结合了水平margin实现两栏自适应布局1.3.1和1.2.1的思路。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{margin:0;padding:0;}
body {
overflow: hidden;
}
.left {
width:100px;
height:300px;
background-color: rgba(255,0,0,0.5);
float: left;
}
.right {
width: 200px;
height:300px;
background-color: rgba(0,0,255,0.5);
float: right;
}
.middle {
height:300px;
margin:0 200px 0 100px;
background-color: rgba(0,255,0,0.5);
}
</style>
</head>
<body>
<div class="left"></div>
<div class="right"></div>
<div class="middle"></div>
</body>
</html>
2.2 绝对定位布局
DOM结构:无所谓,此处用left、middle、right吧,当然如果需求要求中间栏优先渲染,那么可以将middle放在最上面
写法:
- left和right分别绝对定位,这里相对于初始包含块的;
- middle不加定位,用margin-left和margin-right与左栏和右栏隔开,防止被遮挡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
* {margin:0;padding:0;}
.left {
position: absolute;
left: 0; width: 100px;
top:0;height:300px;
background-color: rgba(255,0,0,0.3);
}
.right {
position: absolute;
right:0;width:200px;
top:0;height:300px;
background-color: rgba(0,0,255,0.3);
}
.middle {
height:300px;
margin: 0 200px 0 100px;
background-color: rgba(0,255,0,0.3);
}
</style>
</head>
<body>
<div class="left"></div>
<div class="middle"></div>
<div class="right"></div>
</body>
</html>
疑问,下面的代码中,wrapper为什么不能拉伸?大概原因是wrapper的层叠顺序低,但是,middle的背景色为什么会在wrapper的背景色之上呢,wrapper至少是absolute呀
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
* {margin:0;padding:0;}
#wrapper {
position: absolute;
width:500px;
height:300px;
overflow: hidden;
resize: both;
background-color: yellow;
}
.left {
position: absolute;
left: 0; width: 100px;
top:0;bottom: 0;/*高度与包含块同高*/
background-color: rgba(255,0,0,1);
}
.right {
position: absolute;
right:0;width:200px;
top:0;bottom: 0;/*高度与包含块同高*/
background-color: rgba(0,0,255,1);
}
.middle {
height:200px;
margin: 0 200px 0 100px;
background-color: rgba(0,255,0,1);
}
</style>
</head>
<body>
<div id="wrapper">
<div class="left"></div>
<div class="middle"></div>
<div class="right"></div>
</div>
</body>
</html>
2.3 圣杯布局
DOM结构:middle、left、right(左右两栏顺序无所谓,但是还是左栏在前好看一点)
思路:内容区本身与其padding是间隔的,那么可以将左栏和右栏放置在middle的水平padding区,那么就可以实现middle的内容区与左右栏分隔的效果。
写法:
- 三栏都float:left,左右栏设置宽度,middle栏的宽度设置为100%
- 将左栏拉到上一行,使得其左边缘与包含块左边缘对齐,即margin-left:-100%;这个百分比是相对于包含块的宽度的,包含块为离它最近的block、inline-block、table-cell的content box
- 将右栏拉到上一行,使得其右边缘与包含块右边缘对齐,即margin-left:自身宽度的负值。
- 上述左右栏移动以后会对中间栏造成遮挡,因此采用对包含块元素#box添加padding-left:左栏宽度、padding-right:右栏宽度,且左栏relative,向左移动自身宽度,右栏relative,向右移动自身宽度。
注意:
- 包含块为content box,所以relative以及相应的移动必不可少。
- 注意让父元素包含浮动的子元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
* {margin:0;padding:0;}
#box {
overflow: hidden;/*包含浮动子元素*/
background-color: #8BD400;
padding-left: 100px;
padding-right: 200px;
}
.middle {
float: left;
height:300px;
background-color: yellow;
width: 100%;
}
.left{
float: left;
width: 100px;
height:300px;
background-color: red;
margin-left: -100%;
position: relative;
left:-100px;/*相对其原来的位置,向左移动100px*/
}
.right{
float: left;
width:200px;
height:300px;
background-color: green;
margin-left: -200px;
position: relative;
left:200px;/*相对其原来的位置,向右移动100px,right:-200px;效果一样*/
}
</style>
</head>
<body>
<div id="box">
<div class="middle"></div>
<div class="left"></div>
<div class="right"></div>
</div>
</body>
</html>
疑问:如果DOM中没有#box,那么如果给body设置oveflow:hidden,并不会包含其中的三个浮动子元素,为什么?
2.4 双飞翼布局
DOM结构:middle外面嵌套div、left、right
写法:
- .outerDiv、left、right三者左浮动,.outerDiv宽度100%,left和right固定宽度
- .middle左右margin分别与左右栏宽度相等
- 左右栏通过margin-left换到上一行middle的margin的相应位置
类比:如果只看middle和right,那么与1.3.2中两栏自适应布局(右侧固定左侧自适应)的思路一样
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
* {margin:0;padding:0;}
#box {
overflow: hidden;/*包含浮动子元素*/
}
.outerDiv {
float: left;
width: 100%;
}
.middle {
margin-left: 100px;
margin-right: 200px;/*与左右栏间隔*/
height:300px;
background-color: yellow;
}
.left {
float: left;
width: 100px;
height:300px;
background-color: red;
margin-left: -100%;
}
.right {
float: left;
width:200px;
height:300px;
background-color: green;
margin-left: -200px;
}
</style>
</head>
<body>
<div id="box">
<div class="outerDiv"><!--嵌套的div标签-->
<div class="middle"></div>
</div>
<div class="left"></div>
<div class="right"></div>
</div>
</body>
</html>
2.5 圣杯布局和双飞翼布局的对比
双飞翼布局比圣杯布局多用了一个div,但是少用了4个css属性(少用了左右栏的relative以及相应的偏移量)
2.6 其他可供参考的博客
https://cloud.tencent.com/developer/article/1351068
http://www.cnblogs.com/imwtr/p/4441741.html#top
https://www.jianshu.com/p/81ef7e7094e8 (讲了圣杯布局和双飞翼布局中,关于最小宽度的设置问题)
https://www.cnblogs.com/woodk/p/5147085.html(讲了圣杯布局和双飞翼布局的区别)
https://www.jianshu.com/p/2fe0e6953d0f(讲了圣杯布局和双飞翼布局的其他实现方法)