本文最初发表于博客园, 并在 GitHub 上持续更新前端的系列文章欢迎在 GitHub 上关注我, 一起入门和进阶前端
以下是正文
题目: 谈一谈你对 CSS 盒模型的认识
专业的面试, 一定会问 CSS 盒模型对于这个题目, 我们要回答一下几个方面:
(1)基本概念: contentpaddingmargin
(2)标准盒模型 IE 盒模型的区别不要漏说了 IE 盒模型, 通过这个问题, 可以筛选一部分人
(3)CSS 如何设置这两种模型(即: 如何设置某个盒子为其中一个模型)? 如果回答了上面的第二条, 还会继续追问这一条
(4)JS 如何设置获取盒模型对应的宽和高? 这一步, 已经有很多人答不上来了
(5)实例题: 根据盒模型解释边距重叠
前四个方面是逐渐递增, 第五个方面, 却鲜有人知
(6)BFC(边距重叠解决方案)或 IFC
如果能回答第五条, 就会引出第六条 BFC 是面试频率较高的
总结: 以上几点, 从上到下, 知识点逐渐递增, 知识面从理论 CSSJS, 又回到 CSS 理论
接下来, 我们把上面的六条, 依次讲解
标准盒模型和 IE 盒子模型
标准盒子模型:
IE 盒子模型:
上图显示:
在 CSS 盒子模型 (Box Model) 规定了元素处理元素的几种方式:
width 和 height: 内容的宽度高度(不是盒子的宽度高度)
padding: 内边距
border: 边框
margin: 外边距
CSS 盒模型和 IE 盒模型的区别:
在 标准盒子模型中, width 和 height 指的是内容区域的宽度和高度增加内边距边框和外边距不会影响内容区域的尺寸, 但是会增加元素框的总尺寸
IE 盒子模型中, width 和 height 指的是内容区域 + border+padding 的宽度和高度
CSS 如何设置这两种模型
代码如下:
- /* 设置当前盒子为 标准盒模型(默认) */
- box-sizing: content-box;
- /* 设置当前盒子为 IE 盒模型 */
- box-sizing: border-box;
备注: 盒子默认为标准盒模型
JS 如何设置获取盒模型对应的宽和高
方式一: 通过 DOM 节点的 style 样式获取
element.style.width/height;
缺点: 通过这种方式, 只能获取行内样式, 不能获取内嵌的样式和外链的样式
这种方式有局限性, 但应该了解
方式二(IE 独有的)
element.currentStyle.width/height;
获取到的即时运行完之后的宽高 (三种 css 样式都可以获取) 但这种方式只有 IE 独有
方式三(通用型)
window.getComputedStyle(element).width/height;
方式三和方式二一样只不过, 方式三能兼容 Chrome 火狐是通用型方式
方式 4
element.getBoundingClientRect().width/height;
此 api 的作用是: 获取一个元素的绝对位置绝对位置是视窗 viewport 左上角的绝对位置
此 api 可以拿到四个属性: lefttopwidthheight
总结:
上面的四种方式, 要求能说出来区别, 以及哪个的通用型更强
margin 塌陷 / margin 重叠
标准文档流中, 竖直方向的 margin 不叠加, 只取较大的值作为 margin(水平方向的 margin 是可以叠加的, 即水平方向没有塌陷现象)
PS: 如果不在标准流, 比如盒子都浮动了, 那么两个盒子之间是没有 margin 重叠的现象的
我们来看几个例子
兄弟元素之间
如下图所示:
子元素和父元素之间
- <!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
儿子这个盒子:
父亲这个盒子:
上方代码中, 如果我们给父亲设置一个属性: overflow: hidden, 就可以避免这个问题, 此时父亲的高度是 110px, 这个用到的就是 BFC(下一段讲解)
善于使用父亲的 padding, 而不是儿子的 margin
其实, 这一小段讲的内容与上一小段相同, 都是讲父子之间的 margin 重叠
我们来看一个奇怪的现象现在有下面这样一个结构:(div 中放一个 p)
- <div>
- <p></p>
- </div>
上面的结构中, 我们尝试通过给儿子 p 一个 margin-top:50px; 的属性, 让其与父亲保持 50px 的上边距结果却看到了下面的奇怪的现象:
此时我们给父亲 div 加一个 border 属性, 就正常了:
如果父亲没有 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, 可以让属性是 hiddenauto 最常用
方法 2: 浮动中: float 的属性值不为 none 意思是, 只要设置了浮动, 当前元素就创建了 BFC
方法 3: 定位中: 只要 posiiton 的值不是 static 或者是 relative 即可, 可以是 absolute 或 fixed, 也就生成了一个 BFC
方法 4:display 为 inline-block, table-cell, table-caption, flex, inline-flex
参考链接:
BFC 原理详解
BFC 详解
前端精选文摘: BFC 神奇背后的原理
下面来看几个例子, 看看如何生成 BFC
BFC 的应用
举例 1: 解决 margin 重叠
当父元素和子元素发生 margin 重叠时, 解决办法: 给子元素增加一个父元素, 给这个父元素创建 BFC
比如说, 针对下面这样一个 div 结构:
- <div class="father">
- <p class="son">
- </p>
- </div>
上面的 div 结构中, 如果父元素和子元素发生 margin 重叠, 我们可以给子元素创建一个 BFC, 就解决了:
- <div class="father">
- <p class="son" style="overflow: hidden">
- </p>
- </div>
因为第二条: BFC 区域是一个独立的区域, 不会影响外面的元素
举例 2:BFC 区域不与 float 区域重叠:
针对下面这样一个 div 结构;
- <!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>
效果如下:
上图中, 由于右侧标准流里的元素, 比左侧浮动的元素要高, 导致右侧有一部分会跑到左边的下面去
如果要解决这个问题, 可以将右侧的元素创建 BFC, 因为第三条: BFC 区域不与 float box 区域重叠解决办法如下:(将 right 区域添加 overflow 属性)
<div class="right" style="overflow: hidden">
右侧, smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,
</div>
上图表明, 解决之后, father-layout 的背景色显现出来了, 说明问题解决了
举例 3: 清除浮动
现在有下面这样的结构:
- <!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>
效果如下:
上面的代码中, 儿子浮动了, 但由于父亲没有设置高度, 导致看不到父亲的背景色 (此时父亲的高度为 0) 正所谓有高度的盒子, 才能关住浮动
如果想要清除浮动带来的影响, 方法一是给父亲设置高度, 然后采用隔墙法方法二是 BFC: 给父亲增加 overflow=hidden 属性即可, 增加之后, 效果如下:
为什么父元素成为 BFC 之后, 就有了高度呢? 这就回到了第四条: 计算 BFC 的高度时, 浮动元素也参与计算意思是, 在计算 BFC 的高度时, 子元素的 float box 也会参与计算
来源: https://www.cnblogs.com/smyhvae/p/8512617.html