布局中会涉及到两个CSS知识:浮动、定位。这里详细说说关于浮动方面的知识。
首先要知道,浮动设计的初衷是为了实现文字环绕图片的效果。所以元素浮动后表现出的一些特性与这个实现目的是有密切关系的。
1.浮动的一些特性
1.1 破坏性
看看下面的Demo:
<div style="border:1px solid;">
<img src="./tb_index/images/1.png" alt="" style="width: 100px; height:100px; float:left">
</div>
当img设置为浮动后,父标签div发生了“坍塌”。这是因为当某一元素发生浮动时,它就脱离了文档流。普通文本流中的父标签就看不到它。此时div没被任何元素撑起来,所以就发生了“坍塌”。当然,它并非是完全脱离文档流(像绝对定位这种的就是完全脱离了文档流),因为文字是能够看到浮动元素的。
为什么float被设计成具有破坏性?比较下面的图片就能明白了:
让父元素塌陷就是为了实现文字环绕图片的效果。
1.2 包裹性
如下Demo:
<div style="border:1px solid; float:left;">
娃哈哈哈哈哈哈哈哈哈哈哈哈哈哈
</div>
块级元素默认会占满整个屏幕宽度。当把一个块级元素设置为浮动时,他就变得紧凑了起来了,把内容紧紧地包裹起来,这个就是浮动元素的包裹性。是不是很像inline-block?注意!!!仅仅是表现上像inline-block而已,其实在DOM中它的display仍然为block.
为什么设计成这样?还是那句话--为了实现文字环绕。上面说的是文字环绕文字,如果是文字环绕div呢?此时如果div不包裹起来,外面的文字怎么实现环绕呢?
2.CSS布局之两栏布局
2.1 双inline-block
<div class="main">
<div class="left">left</div>
<div class="right">right</div>
</div>
.main{
border:1px solid;
width: 100%;
font-size: 0; /*去掉两个inline-block之间的空格 */
}
.left{
display:inline-block;
box-sizing: border-box;
width: 100px;
height: 100px;
font-size:14px;
vertical-align: top; /*顶端对齐*/
background-color:blue;
}
.right{
display:inline-block;
box-sizing: border-box;
width: calc(100% - 100px);
height: 100px;
font-size: 14px;
vertical-align: top;
background-color:green;
}
缺点:
- 需要计算左栏的高度,如果栏与栏之间有距离,还要算上间隔,且需要设置box-sizing。
- 需要设置顶端对齐。
- 需要消除空格的影响。
2.2 双float
相对于双inline-block方法,双float方法不需要消除空格的影响,也不需要设置顶端对齐。
.main{
width: 100%;
overflow: hidden;
border: 1px solid;
}
.left{
float: left;
box-sizing: border-box;
width: 100px;
height: 100px;
background-color:blue;
}
.right{
float: left;
box-sizing: border-box;
width: calc(100% - 100px);
height: 100px;
background-color:green;
}
缺点:
- 还是得需要计算左栏和两栏距离的大小。
- 父元素需要包含浮动,否则会发生“坍塌”。
2.3 float+margin-left
上面的两种方法中,右栏是通过css的calc的函数来指定宽度从而实现流动特性的。之所以需要借助calc,是因为浮动元素和inline-block元素是具有包裹性的,在不指定width的情况下,它们会紧紧地包裹住内容。这里的实现是通过block元素默认填充满父元素的特点来实现流动特性的。如下:
.main{
width: 100%;
overflow: hidden;
border: 1px solid;
}
.left{
float: left;
box-sizing: border-box;
width: 100px;
height: 100px;
background-color:blue;
}
.right{
box-sizing: border-box;
margin-left: 100px;
height: 100px;
background-color:green;
}
缺点:
- 还是得计算做栏的宽度和两栏之间的距离。
- 外层div需要包含浮动元素。
2.4 float+BFC
块元素是看不见浮动元素的,上例中如果不给右栏设置margin-left,右栏就会有一部分与浮动元素发生重叠。此例中通过overflow:hidden触发右栏的BFC,具有BFC的元素不会与浮动元素发生重叠。代码如下:
.main{
width: 100%;
overflow: hidden;
border: 1px solid;
}
.left{
float: left;
box-sizing: border-box;
margin-right: 20px;
width: 100px;
height: 100px;
background-color:blue;
}
.right{
overflow: hidden; /*触发BFC*/
box-sizing: border-box;
height: 100px;
background-color:green;
}
需要注意的是:假如两栏有20px的距离,那么通过给浮动的左栏设置:margin-right:20px即可。通过给右栏设置:margin-left:20px是无法实现效果的(需要设置:margin-left:120px才能生效,也就是说还得计算左栏的宽度)。
缺点:
- 需要包含浮动元素
2.5 flex
如果不考虑那些老掉牙的浏览器(IE6等)的兼容性的话,flex布局还是挺好用的。如下:
.main{
display: flex;
}
.left{
flex: 0 0 100px;
background-color:blue;
}
.right{
flex: 1 1 auto;
background-color:green;
}
3.三栏布局
3.1 圣杯布局
圣杯布局中左右两栏宽度固定,中间宽度自适应,俗称固比固。实现方法是:通过给外层容器container设置左右padding来给左右两栏空出位置,给left、right和main三栏设置浮动,通过负的margin将左右两栏拉到与main栏同一行,最后通过相对定位将左右两栏定位到padding的位置上。
<div class="container">
<div class="main">main</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
body{
min-width: 600px;
}
.container {
padding: 0 200px;
}
.main {
float: left;
width: 100%;
height: 100px;
background-color: blue;
}
.left {
position: relative;
float: left;
right: 200px;
margin-left: -100%;
width: 200px;
height: 100px;
background-color: yellow;
}
.right {
position: relative;
float: left;
left: 200px;
margin-left: -200px;
width: 200px;
height: 100px;
background-color: green;
}
圣杯布局中需要注意的点:
- 不要给容器.container指定宽度(min-xxx和max-xxx不算)。
- .left和.main中的100%宽度参考的是.container的宽度,而且是除了padding外的宽度。
- 当浏览器窗口缩小到600以下时,此时.main栏小于.left栏,会导致布局断行。需要给body指定一个最小宽度min-width:600px(也可以给.container指定最小宽度min-width: 200px)。
3.2 双飞翼布局
与圣杯布局一样,都是为了实现固比固布局,都是通过负margin将左右两栏拉到与main相同一行。不同之处在于:圣杯是通过三栏的容器.container中的padding来为左右两栏腾出空间,而双飞翼布局中需要给main套一层div,也就是下面代码中的main-wrap,且main-wrap设置浮动。之后通过里层的main设置margin-left和margin-right来为两栏腾出空间。
<body>
<div class="main-wrap">
<div class="main">main</div>
</div>
<div class="left">left</div>
<div class="right">right</div>
</body>
.main-wrap {
float:left;
width:100%;
}
.main {
margin-left: 200px;
margin-right: 200px;
height: 100px;
background-color: blue;
}
.left {
float: left;
margin-left: -100%;
width: 200px;
height: 100px;
background-color: yellow;
}
.right {
float: left;
margin-left: -200px;
width: 200px;
height: 100px;
background-color: green;
}