forked from theluyuan/Web
439 lines
11 KiB
Markdown
439 lines
11 KiB
Markdown
|
||
|
||
|
||
> 本文最初发表于[博客园](http://www.cnblogs.com/smyhvae/p/8512617.html),并在[GitHub](https://github.com/smyhvae/Web)上持续更新**前端的系列文章**。欢迎在GitHub上关注我,一起入门和进阶前端。
|
||
|
||
> 以下是正文。
|
||
|
||
|
||
|
||
## 题目:谈一谈你对CSS盒模型的认识
|
||
|
||
专业的面试,一定会问 CSS 盒模型。对于这个题目,我们要回答一下几个方面:
|
||
|
||
(1)基本概念:content、padding、margin。
|
||
|
||
(2)标准盒模型、IE盒模型的区别。不要漏说了IE盒模型,通过这个问题,可以筛选一部分人。
|
||
|
||
(3)CSS如何设置这两种模型(即:如何设置某个盒子为其中一个模型)?如果回答了上面的第二条,还会继续追问这一条。
|
||
|
||
(4)JS如何设置、获取盒模型对应的宽和高?这一步,已经有很多人答不上来了。
|
||
|
||
(5)实例题:根据盒模型解释**边距重叠**。
|
||
|
||
前四个方面是逐渐递增,第五个方面,却鲜有人知。
|
||
|
||
(6)BFC(边距重叠解决方案)或IFC。
|
||
|
||
如果能回答第五条,就会引出第六条。BFC是面试频率较高的。
|
||
|
||
**总结**:以上几点,从上到下,知识点逐渐递增,知识面从理论、CSS、JS,又回到CSS理论。
|
||
|
||
接下来,我们把上面的六条,依次讲解。
|
||
|
||
|
||
## 标准盒模型和IE盒子模型
|
||
|
||
|
||
标准盒子模型:
|
||
|
||
![](http://7sby7r.com1.z0.glb.clouddn.com/2015-10-03-css-27.jpg)
|
||
|
||
IE盒子模型:
|
||
|
||
![](http://7sby7r.com1.z0.glb.clouddn.com/2015-10-03-css-30.jpg)
|
||
|
||
上图显示:
|
||
|
||
|
||
在 CSS 盒子模型 (Box Model) 规定了元素处理元素的几种方式:
|
||
|
||
|
||
- width和height:**内容**的宽度、高度(不是盒子的宽度、高度)。
|
||
- padding:内边距。
|
||
- border:边框。
|
||
- margin:外边距。
|
||
|
||
CSS盒模型和IE盒模型的区别:
|
||
|
||
- 在 <font color="#0000FF">**标准盒子模型**</font>中,<font color="#0000FF">**width 和 height 指的是内容区域**</font>的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。
|
||
|
||
- <font color="#0000FF">**IE盒子模型**</font>中,<font color="#0000FF">**width 和 height 指的是内容区域+border+padding**</font>的宽度和高度。
|
||
|
||
|
||
|
||
## CSS如何设置这两种模型
|
||
|
||
|
||
代码如下:
|
||
|
||
|
||
```javascript
|
||
/* 设置当前盒子为 标准盒模型(默认) */
|
||
box-sizing: content-box;
|
||
|
||
/* 设置当前盒子为 IE盒模型 */
|
||
box-sizing: border-box;
|
||
```
|
||
|
||
|
||
备注:盒子默认为标准盒模型。
|
||
|
||
|
||
## JS如何设置、获取盒模型对应的宽和高
|
||
|
||
|
||
### 方式一:通过DOM节点的 style 样式获取
|
||
|
||
|
||
```javascript
|
||
element.style.width/height;
|
||
```
|
||
|
||
缺点:通过这种方式,只能获取**行内样式**,不能获取`内嵌`的样式和`外链`的样式。
|
||
|
||
这种方式有局限性,但应该了解。
|
||
|
||
|
||
|
||
### 方式二(通用型)
|
||
|
||
|
||
```javascript
|
||
window.getComputedStyle(element).width/height;
|
||
```
|
||
|
||
|
||
方式二能兼容 Chrome、火狐。是通用型方式。
|
||
|
||
|
||
### 方式三(IE独有的)
|
||
|
||
|
||
```javascript
|
||
element.currentStyle.width/height;
|
||
```
|
||
|
||
和方式二相同,但这种方式只有IE独有。获取到的即时运行完之后的宽高(三种css样式都可以获取)。
|
||
|
||
|
||
### 方式四
|
||
|
||
|
||
```javascript
|
||
element.getBoundingClientRect().width/height;
|
||
```
|
||
|
||
此 api 的作用是:获取一个元素的绝对位置。绝对位置是视窗 viewport 左上角的绝对位置。
|
||
|
||
此 api 可以拿到四个属性:left、top、width、height。
|
||
|
||
**总结:**
|
||
|
||
上面的四种方式,要求能说出来区别,以及哪个的通用型更强。
|
||
|
||
|
||
## margin塌陷/margin重叠
|
||
|
||
|
||
**标准文档流中,竖直方向的margin不叠加,只取较大的值作为margin**(水平方向的margin是可以叠加的,即水平方向没有塌陷现象)。
|
||
|
||
PS:如果不在标准流,比如盒子都浮动了,那么两个盒子之间是没有margin重叠的现象的。
|
||
|
||
|
||
我们来看几个例子。
|
||
|
||
|
||
### 兄弟元素之间
|
||
|
||
如下图所示:
|
||
|
||
![](http://img.smyhvae.com/20170805_0904.png)
|
||
|
||
|
||
### 子元素和父元素之间
|
||
|
||
|
||
```html
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Document</title>
|
||
<style>
|
||
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
|
||
.father {
|
||
background: green;
|
||
|
||
}
|
||
|
||
/* 给儿子设置margin-top为10像素 */
|
||
.son {
|
||
height: 100px;
|
||
margin-top: 10px;
|
||
background: red;
|
||
}
|
||
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="father">
|
||
<div class="son"></div>
|
||
</div>
|
||
</body>
|
||
</html>
|
||
|
||
```
|
||
|
||
上面的代码中,儿子的height是 100px,magin-top 是10px。注意,此时父亲的 height 是100,而不是110。因为儿子和父亲在竖直方向上,共一个margin。
|
||
|
||
儿子这个盒子:
|
||
|
||
![](http://img.smyhvae.com/20180305_2216.png)
|
||
|
||
父亲这个盒子:
|
||
|
||
![](http://img.smyhvae.com/20180305_2217.png)
|
||
|
||
|
||
上方代码中,如果我们给父亲设置一个属性:`overflow: hidden`,就可以避免这个问题,此时父亲的高度是110px,这个用到的就是BFC(下一段讲解)。
|
||
|
||
|
||
### 善于使用父亲的padding,而不是儿子的margin
|
||
|
||
> 其实,这一小段讲的内容与上一小段相同,都是讲父子之间的margin重叠。
|
||
|
||
我们来看一个奇怪的现象。现在有下面这样一个结构:(div中放一个p)
|
||
|
||
```
|
||
<div>
|
||
<p></p>
|
||
</div>
|
||
```
|
||
|
||
上面的结构中,我们尝试通过给儿子`p`一个`margin-top:50px;`的属性,让其与父亲保持50px的上边距。结果却看到了下面的奇怪的现象:
|
||
|
||
![](http://img.smyhvae.com/20170806_1537.png)
|
||
|
||
|
||
此时我们给父亲div加一个border属性,就正常了:
|
||
|
||
![](http://img.smyhvae.com/20170806_1544.png)
|
||
|
||
|
||
如果父亲没有border,那么儿子的margin实际上踹的是“流”,踹的是这“行”。所以,父亲整体也掉下来了。
|
||
|
||
**margin这个属性,本质上描述的是兄弟和兄弟之间的距离; 最好不要用这个marign表达父子之间的距离。**
|
||
|
||
所以,如果要表达父子之间的距离,我们一定要善于使用父亲的padding,而不是儿子的margin。
|
||
|
||
|
||
## BFC(边距重叠解决方案)
|
||
|
||
### BFC的概念
|
||
|
||
BFC(Block Formatting Context):块级格式化上下文。你可以把它理解成一个独立的区域。
|
||
|
||
另外还有个概念叫IFC。不过,BFC问得更多。
|
||
|
||
### BFC 的原理/BFC的布局规则【非常重要】
|
||
|
||
BFC 的原理,其实也就是 BFC 的渲染规则(能说出以下四点就够了)。包括:
|
||
|
||
- (1)BFC **内部的**子元素,在垂直方向,**边距会发生重叠**。
|
||
|
||
- (2)BFC在页面中是独立的容器,外面的元素不会影响里面的元素,反之亦然。(稍后看`举例1`)
|
||
|
||
- (3)**BFC区域不与旁边的`float box`区域重叠**。(可以用来清除浮动带来的影响)。(稍后看`举例2`)
|
||
|
||
- (4)计算BFC的高度时,浮动的子元素也参与计算。(稍后看`举例3`)
|
||
|
||
### 如何生成BFC
|
||
|
||
有以下几种方法:
|
||
|
||
- 方法1:overflow: 不为vidible,可以让属性是 hidden、auto。【最常用】
|
||
|
||
- 方法2:浮动中:float的属性值不为none。意思是,只要设置了浮动,当前元素就创建了BFC。
|
||
|
||
- 方法3:定位中:只要posiiton的值不是 static或者是relative即可,可以是`absolute`或`fixed`,也就生成了一个BFC。
|
||
|
||
- 方法4:display为inline-block, table-cell, table-caption, flex, inline-flex
|
||
|
||
参考链接:
|
||
|
||
- [BFC原理详解](https://segmentfault.com/a/1190000006740129)
|
||
|
||
|
||
- [BFC详解](https://www.jianshu.com/p/bf927bc1bed4)
|
||
|
||
|
||
- [前端精选文摘:BFC 神奇背后的原理](https://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html)
|
||
|
||
|
||
下面来看几个例子,看看如何生成BFC。
|
||
|
||
|
||
|
||
### BFC 的应用
|
||
|
||
|
||
**举例1:**解决 margin 重叠
|
||
|
||
当父元素和子元素发生 margin 重叠时,解决办法:**给子元素增加一个父元素,给这个父元素创建BFC**。
|
||
|
||
比如说,针对下面这样一个 div 结构:
|
||
|
||
|
||
```html
|
||
<div class="father">
|
||
<p class="son">
|
||
</p>
|
||
</div>
|
||
```
|
||
|
||
上面的div结构中,如果父元素和子元素发生margin重叠,我们可以给子元素创建一个 BFC,就解决了:
|
||
|
||
|
||
```html
|
||
<div class="father">
|
||
<p class="son" style="overflow: hidden">
|
||
</p>
|
||
</div>
|
||
```
|
||
|
||
因为**第二条:BFC区域是一个独立的区域,不会影响外面的元素**。
|
||
|
||
|
||
**举例2**:BFC区域不与float区域重叠:
|
||
|
||
针对下面这样一个div结构;
|
||
|
||
```html
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Document</title>
|
||
<style>
|
||
|
||
.father-layout {
|
||
background: pink;
|
||
}
|
||
|
||
.father-layout .left {
|
||
float: left;
|
||
width: 100px;
|
||
height: 100px;
|
||
background: green;
|
||
}
|
||
|
||
.father-layout .right {
|
||
height: 150px; /*右侧标准流里的元素,比左侧浮动的元素要高*/
|
||
background: red;
|
||
}
|
||
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<section class="father-layout">
|
||
<div class="left">
|
||
左侧,生命壹号
|
||
</div>
|
||
<div class="right">
|
||
右侧,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,
|
||
</div>
|
||
</section>
|
||
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
效果如下:
|
||
|
||
![](http://img.smyhvae.com/20180306_0825.png)
|
||
|
||
上图中,由于右侧标准流里的元素,比左侧浮动的元素要高,导致右侧有一部分会跑到左边的下面去。
|
||
|
||
**如果要解决这个问题,可以将右侧的元素创建BFC**,因为**第三条:BFC区域不与`float box`区域重叠**。解决办法如下:(将right区域添加overflow属性)
|
||
|
||
```html
|
||
<div class="right" style="overflow: hidden">
|
||
右侧,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,
|
||
</div>
|
||
```
|
||
|
||
|
||
![](http://img.smyhvae.com/20180306_0827.png)
|
||
|
||
上图表明,解决之后,`father-layout`的背景色显现出来了,说明问题解决了。
|
||
|
||
|
||
|
||
**举例3:**清除浮动
|
||
|
||
现在有下面这样的结构:
|
||
|
||
|
||
```html
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Document</title>
|
||
<style>
|
||
|
||
.father {
|
||
background: pink;
|
||
}
|
||
|
||
.son {
|
||
float: left;
|
||
background: green;
|
||
}
|
||
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<section class="father">
|
||
<div class="son">
|
||
生命壹号
|
||
</div>
|
||
|
||
</section>
|
||
</body>
|
||
</html>
|
||
```
|
||
|
||
效果如下:
|
||
|
||
![](http://img.smyhvae.com/20180306_0840.png)
|
||
|
||
上面的代码中,儿子浮动了,但由于父亲没有设置高度,导致看不到父亲的背景色(此时父亲的高度为0)。正所谓**有高度的盒子,才能关住浮动**。
|
||
|
||
如果想要清除浮动带来的影响,方法一是给父亲设置高度,然后采用隔墙法。方法二是 BFC:给父亲增加 `overflow=hidden`属性即可, 增加之后,效果如下:
|
||
|
||
![](http://img.smyhvae.com/20180306_0845.png)
|
||
|
||
为什么父元素成为BFC之后,就有了高度呢?这就回到了**第四条:计算BFC的高度时,浮动元素也参与计算**。意思是,**在计算BFC的高度时,子元素的float box也会参与计算**。
|
||
|
||
|
||
|
||
## 我的公众号
|
||
|
||
想学习<font color=#0000ff>**代码之外的软技能**</font>?不妨关注我的微信公众号:**生命团队**(id:`vitateam`)。
|
||
|
||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||
|
||
![](http://img.smyhvae.com/2016040102.jpg)
|
||
|
||
|
||
|