一.BFC
1.1 定义
BFC-Block Formating Context(块级格式化上下文)
- 内部的Box会在垂直方向上一个接一个的放置
- 同一个BFC的两个相邻Box的margin会发生重叠
- 计算BFC的高度时,浮动子元素也参与计算
- BFC的区域不会与float box重叠。
- BFC是一个完全独立的空间,让空间里的子元素不会影响到外面的布局
当BFC外部存在浮动时,它不应该影响BFC内部Box的布局,BFC会通过变窄(如果没有设置宽度的话),而不与浮动有重叠
当BFC内部有浮动时,为了不影响外部元素的布局,BFC计算高度时会包括浮动的高度。 避免margin重叠也是这样的一个道理。
1.2 触发原理
body
float:left/right
position:fixed/absolute
display:inline-block/table-cell/fixed
overfolw不为visible
1.3 BFC解决的问题
1.3.1 margin合并问题
<div class="box1"></div>
<div class="box2"></div>
复制代码
div{
width:100px;
height:100px;
}
.box1{
background-color: red;
border:1px solid blue;
padding:10px;
margin-bottom:30px;
}
.box2{
background-color: green;
border:1px solid blue;
padding:10px;
margin-top:20px;
}
复制代码
两个相邻的盒子在垂直方向上的margin值出现了合并状态,合并为两者margin较大的那个值,并且使用border或者padding是无法阻止这一现象的。
原因:Box垂直方向的距离由margin决定。属于同一个BFC(上例中是body根元素的BFC)的两个相邻Box的margin会发生重叠
<div class="container">
<div class="box1"></div>
</div>
<div class="box2"></div>
复制代码
.box1{
background-color: red;
margin-bottom:130px;
width:100px;
height:100px;
}
.box2{
background-color: green;
margin-top:120px;
width:100px;
height:100px;
}
.container{
overflow: hidden;
}
复制代码
解决办法就是让.box1作为新BFC元素.container的子元素让其于body这个BFC元素的子元素.box2处于不同的BFC中,那么就可以解决margin合并的问题
<div class="container">
<div class="box1"></div>
</div>
复制代码
.box1{
background-color: red;
margin-top:150px;
width:100px;
height:100px;
}
.container{
width:200px;
height:200px;
margin-top:100px;
background-color: green;
}
复制代码
当父元素有margin值且子元素也有margin值的时候,取两者的最大值进行合并,并且还存在另一个问题就是为什么子元素的margin不是相对父元素的呢,这就涉及到margin-top塌陷的问题
这是由于此时父子盒子都处于body这个BFC之中,三者属于同一个BFC,那么一开始body也是有外边距的,所以会先和父盒子的100进行合并,其次在与子盒子进行合并就形成了最后的150px;
.box1{
background-color: red;
margin-top:150px;
width:100px;
height:100px;
}
.container{
width:200px;
height:200px;
margin-top:100px;
background-color: green;
overflow: hidden;
}
body{
display: flex;
}
复制代码
让父盒子形成一个新的BFC,那么与body这个BFC元素就不是同一个,则margin不会合并,那么就是108px。其次由于创建了BFC的元素不会和它的子元素发生外边距叠加。
1.3.2 margin-top坍塌问题
<div class="container">
<div class="box"></div>
</div>
复制代码
.container{
width:500px;
height:500px;
background-color: blue;
padding-top:10px;
/* border:1px solid red; */
}
.box{
width:100px;
height:100px;
background-color: green;
margin-top:50px;
}
复制代码
当父盒子有border-top或者有padding-top属性时,子盒子与父盒子不处于毗邻状态,则不会发生margin-top塌陷问题
<div class="container">
<div class="box"></div>
</div>
复制代码
.container{
width:500px;
height:500px;
background-color: blue;
}
.box{
width:100px;
height:100px;
background-color: green;
margin-top:50px;
}
复制代码
如上述情况就会发生marin-top塌陷问题,指子元素设置了margin-top值但是它不相对父盒子发生位移,而带着父盒子于上一个外层元素发生位移
<div class="container">
<div class="box"></div>
</div>
复制代码
.container{
width:500px;
height:500px;
/* overflow:hidden; */
/* position: absolute; */
position:fixed;
background-color: blue;
}
.box{
width:100px;
height:100px;
background-color: green;
margin-top:50px;
}
复制代码
触发父盒子的BFC来解决这一问题
1.3.3 高度坍塌问题(float引发的高度坍塌问题)
<div class="box">
<div class="box1"></div>
<div class="box2"></div>
</div>
复制代码
.box{
width:200px;
border:2px solid red;
}
.box1{
float:left;
width: 100px;
height:100px;
background-color: orange;
}
.box2{
float:left;
width: 100px;
height:100px;
background-color: green;
}
复制代码
.box{
width:200px;
border:2px solid red;
/* float:left ; */
overflow:hidden;
}
.box1{
float:left;
width: 100px;
height:100px;
background-color: orange;
}
.box2{
float:left;
width: 100px;
height:100px;
background-color: green;
}
复制代码
触发BFC来满足BFC规则中的计算BFC的高度时,浮动元素也参与计算
1.3.4 环绕问题(float引发的环绕问题)
<div class="box"></div>
<div class="box1">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Praesentium cupiditate veniam ratione dicta eaque dolore ullam, minima at, maiores veritatis expedita repudiandae rem modi odit ab molestias, eveniet magni qui!</div>
复制代码
.box{
width:100px;
height: 100px;
float:left;
background-color: #000;
}
.box1{
/* float: left; */
width:200px;
height:200px;
background-color: orange;
}
复制代码
由于第一个元素浮动了脱离了文档流,而第二个块级元素识别不出浮动元素的位置,所以会覆盖上去。
.box{
width:100px;
height: 100px;
float:left;
background-color: #000;
}
.box1{
float: left;
width:200px;
height:200px;
background-color: orange;
}
复制代码
触发BFC根据BFC规则BFC的区域不会与float box重叠可以防止覆盖的现象
参考文档
二.浮动
2.1 浮动
float设计之初是为了实现文字环绕的效果,但是带来的是破坏了正常的文档流,但是其不会覆盖掉之前的文档流。毕竟浮动的元素对前面已经布局好的元素并不会带来影响,影响的是后续的元素。
<div class="container">
<div class="box1"></div>
</div>
<div class="content">wenzi</div>
复制代码
.container{
width:200px;
border:1px solid red;
}
.box1{
width:100px;
height:100px;
background-color: green;
float: left;
}
.content{
width:200px;
height:200px;
background-color: blue;
}
复制代码
浮动的元素并没有覆盖掉文字
浮动带来的影响:
首先造成父元素高度的坍塌
其次因为高度坍塌从而影响后续元素的布局
2.2 清除浮动
2.2.1 触发BFC(BFC不会与float box重叠)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
.box{
width:200px;
border:10px solid #000;
overflow:hidden;
/* 清除浮动但是如果需要滚动条啥的需求怎么办呢 所以这种方法也不好 */
}
.box1{
float: left;
width:100px;
height:100px;
background-color: green;
}
.box2{
float: left;
width:100px;
height:100px;
background-color: orange;
}
</style>
<body>
<div class="box">
<div class="box1"></div>
<div class="box2"></div>
</div>
</body>
</html>
复制代码
2.2.2 clear:both
/*清除浮动的最佳方法*/
ul::after,
div::after{
content: "";
display:block;
clear:both;
}
复制代码
2.2.3 设置清除浮动的类
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
.box{
width:200px;
border:10px solid #000;
}
.box1{
float: left;
width:100px;
height:100px;
background-color: green;
}
.box2{
float: left;
width:100px;
height:100px;
background-color: orange;
}
/*清除浮动的次品方法*/
.fixclear{
clear:both
}
</style>
<body>
<div class="box">
<div class="box1"></div>
<div class="box2"></div>
<p class='fixclear'></p>
</div>
</body>
<script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
三.绝对定位
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
.container{
width:200px;
border:1px solid red;
}
.box1{
width:100px;
height:100px;
background-color: green;
position:absolute;
}
.content{
width:200px;
height:200px;
background-color: blue;
}
</style>
<body>
<div class="container">
<div class="box1"></div>
</div>
<div class="content">wenzi</div>
</body>
<script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
绝对定位的元素会覆盖。
四.三栏布局
4.1 flex实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
#header,#footer{
height: 50px;
width: 100%;
border: 1px solid;
background-color: grey;
}
#content{
display: flex;
height:500px;
}
#left,#right{
flex-basis: 200px;
background-color: green;
}
#left{
order:1
}
#middle{
background-color: blue;
flex-grow:1;
order:2;
}
#right{
order:3;
}
</style>
<body>
<div class="wrap">
<div id="header">header</div>
<div id="content">
<div id="middle">middle</div>
<div id="left">left</div>
<div id="right">right</div>
</div>
<div id="footer">footer</div>
</div>
</body>
<script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
4.2 圣杯布局(使用padding)
需要解决的问题:
- margin-left:-100%怎么理解
- 为什么需要定位
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
#header,#footer{
height: 50px;
width: 100%;
border: 1px solid;
background-color: grey;
}
#content{
overflow: hidden;
padding: 0px 200px;/*为了让文字显现出来*/
}
#left,#right{
width: 200px;
height: 200px;
background-color:pink;
}
#middle{
background-color: green;
width: 100%;/*相对于内容的100%*/
height: 200px;
}
#middle,#left,#right{
float: left;
}
#left{
/*这里怎么理解 margin-left是自身的左边界相对于上一个元素的右边界进行位移*/
margin-left: -100%;
/*当加入padding值后,由于margin-left是相对于内容的边界进行位移的,加入padding后边界就会产生变化 需要用定位来调整回来*/
position: relative;
left: -200px;
}
#right{
margin-left: -200px;
position: relative;
left: 200px;
}
</style>
<body>
<div class="wrap">
<div id="header">header</div>
<div id="content">
<div id="middle">middle</div>
<div id="left">left</div>
<div id="right">right</div>
</div>
<div id="footer">footer</div>
</div>
</body>
<script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
4.3 双飞翼布局(使用margin)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
#header,#footer{
height: 50px;
width: 100%;
border: 1px solid;
background-color: grey;
}
#left,#right{
width: 200px;
height: 200px;
background-color:pink;
}
#middle{
background-color: green;
width: 100%;
height:200px;
float: left;
}
#content{
overflow: hidden;
}
#left{
float: left;
margin-left:-100%;
/* 当margin-left 为父元素的-100%时,就会上移动一行。,行盒放置时,就会根据margin放置,( 其实应该是左边框距离上个兄弟元素的margin-right ) */
/*相对于上一个浮动的盒子*/
/*这里的margin占满了整行*/
}
#right{
float: left;
margin-left:-200px;
/* 相对left盒子margin */
}
.middle-inner{
margin: 0 200px;
/* 因为现在middle的内容被left和right覆盖了,我们除了考虑设置外围content的padding之外,还可以考虑用margin把middle拉过来; */
}
</style>
<body>
<div class="wrap">
<div id="header">header</div>
<div id="content">
<div id="middle">
<div class="middle-inner">middle</div>
</div>
<div id="left">left</div>
<div id="right">right</div>
</div>
<div id="footer">footer</div>
</div>
</body>
<script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
五.flex布局中涉及的缩放准则
5.1 flex-shrink
5.1.1 只有width
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
.container {
width: 600px;
height: 300px;
display: flex;
}
.left {
width: 500px;
flex-shrink: 2;
background: red;
}
.right {
width: 400px;
flex-shrink: 1;
background: blue;
}
</style>
<body>
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
<script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
.left与.right的宽度明显大于600,所以在设置flex-shrink之后,两者实际的宽度为多少呢?
- 超出部分:500+400-600=300
- 比例:5002 : 4001 = 5:2
- 每块超出内容: 3005/7 3002/7
- .left实际内容: 500 – 300*5/7 = 285.719
- .right实际内容: 500 – 300*2/7 = 314.281
5.1.2 width+padding
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
.container {
width: 600px;
height: 300px;
display: flex;
}
.left {
width: 500px;
flex-shrink: 2;
padding:60px;
background: red;
}
.right {
width: 400px;
padding:40px;
flex-shrink: 1;
background: blue;
}
</style>
<body>
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
<script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
- 超出部分:620+480-600 = 500
- 比例:5002 : 4001 = 5:2
- 每块超出内容: 5005/7 5002/7
- .left实际内容: 620 – 500*5/7 = 262.857
- .right实际内容: 480 – 500*2/7 = 337.143
5.1.3 width+padding+border
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
.container {
width: 600px;
height: 300px;
display: flex;
}
.left {
width: 500px;
flex-shrink: 2;
border:10px solid black;
padding:60px;
background: red;
}
.right {
width: 400px;
border:20px solid black;
padding:40px;
flex-shrink: 1;
background: blue;
}
</style>
<body>
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
<script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
- 超出部分:640+520-600=560
- 比例:5002 : 4001 = 5:2
- 每块超出内容: 5605/7 5602/7
- .left实际内容: 640 – 560*5/7 = 240
- .right实际内容: 520 – 560*2/7 = 360
5.1.4 width+padding+border+margin
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
.container {
width: 600px;
height: 300px;
display: flex;
}
.left {
width: 500px;
flex-shrink: 2;
margin:0 10px;
border:10px solid black;
padding:60px;
background: red;
}
.right {
width: 400px;
border:20px solid black;
padding:40px;
margin:0 20px;
flex-shrink: 1;
background: blue;
}
</style>
<body>
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
<script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
- 超出部分:660+560-600=620
- 比例:5002 : 4001 = 5:2
- 每块超出内容: 6205/7 6202/7
- .left实际内容: 660 – 620*5/7 = 217.142
- .right实际内容: 560 – 620*2/7 = 382.857
由上述四种情况总结得出 超出的部分必须由实际内容(width+border+padding+margin)来计算 而比列是由width来计算所以压缩的是真正内容的值
5.2 flex-grow
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
* {
padding: 0;
margin: 0;
}
.container {
width: 600px;
height: 300px;
display: flex;
}
.left {
width: 100px;
flex-grow: 3;
background: red;
}
.right {
width: 200px;
flex-grow:2;
background: blue;
}
</style>
<body>
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
<script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
- 多余部分:600-100-200=300
- 比例:3 : 2
- 每块超出内容: 3003/5 3002/5
- .left实际内容: 100 + 300*3/5 = 280
- .right实际内容: 200 + 300*2/5 = 320
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>Document</title>
<link rel="stylesheet" type="text/css" href="" />
</head>
<style type="text/css">
/*真正占用空间等于 实际内容大小+padding+border+margin(margin到底算不算)*/
/*剩余空间等于 实际内容大小减去最外层盒子容量(盒子有padding border咋办)*/
/*实际分配的比例 仅仅是实际内容大小的比例*/
/*grow和shrink的比例是按照内容大小为比列 然后根据剩余空间来分配的 */
/*如果grow和shrink的值已经小于1了 就相当于其本身就是比例了*/
* {
padding: 0;
margin: 0;
}
.container {
width: 600px;
height: 300px;
display: flex;
}
.left {
width: 100px;
flex-grow: 0.3;
background: red;
}
.right {
width: 200px;
flex-grow:0.2;
background: blue;
}
</style>
<body>
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
<script src="" type="text/javascript" charset="utf-8"></script>
</html>
复制代码
- left的宽度 100+300*0.3 = 190
- righ的宽度 200+300*0.2 = 260