CSS 之 盒模型和 BFC | 青训营笔记

92 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第 2 天

盒模型

之前在项目中有见过 box-sizing: border-box;,但并没有了解过它究竟是做什么用的。

box-sizing是 CSS3 新增的能够更改盒模型的属性。假设我们有这样两个容器 <div id="border-box" class="box-sizing" /><div id="content-box" class="box-sizing" />

.box-sizing {
  display: inline-block;
  width: 300px;
  height: 100px;
  margin: 30px;
  padding: 20px;
  border: 10px solid transparent;
}

IE 盒模型:box-sizing: border-box;

image.png

.box-sizing #border-box {
  box-sizing: border-box;
}
document.getElementById("box-sizing-test").clientHeight // 80
document.getElementById("box-sizing-test").offsetHeight // 100

W3C 盒模型(默认):box-sizing: content-box;

image.png

.box-sizing #content-box {
  box-sizing: content-box;
}
document.getElementById("box-sizing-test").clientHeight // 140
document.getElementById("box-sizing-test").offsetHeight // 160

总结一下

image.png

IE 盒模型
border-box
W3C 盒模型
content-box
contentheight - padding * 2 - border * 2height
clientHeightcontent + padding * 2

(即 height - border * 2)
content + padding * 2
offsetHeightheightheight + padding * 2 + border * 2

参考:《W3C盒模型和IE盒模型的区别》

外边距塌陷(margin collapse)

垂直方向相邻元素(上下)外边距塌陷

假设有如下两个元素

<div style="margin: 10px; background-color: pink;">top 元素</div>
<div style="margin: 20px; background-color: skyblue;">bottom 元素</div>

image.png

它们之间的间距是 20px 而不是 30px。

注意:只有上下外边距会塌陷,左右外边距不会。

父子元素(上下)外边距塌陷

<div style="margin: 20px;background-color: skyblue;">
  <div style="margin: 30px;background-color: skyblue;">inside 元素</div>
</div>

image.png

塌陷特性:同正同负取绝对值最大,正负相加。

参考:《CSS中外边距(margin)塌陷和合并的问题(初学者必看)》

其实当相邻或父子元素是 inline-block 的话,这种情况不会产生,或者给父元素设置 overflow: auto;overflow: hidden; 以触发 BFC,用以解决父子外边距塌陷的问题。

那么下一个问题就粗线了。

什么是 BFC

BFC 全称:Block Formatting Context, 名为 "块级格式化上下文"。

W3C官方解释为:BFC它决定了元素如何对其内容进行定位,以及与其它元素的关系和相互作用,当涉及到可视化布局时,Block Formatting Context提供了一个环境,HTML在这个环境中按照一定的规则进行布局。

简单来说就是,BFC是一个完全独立的空间(布局环境),让空间里的子元素不会影响到外面的布局。

最常见的是,给元素设置了 display: inline-block; 之后,不论是块级元素或行内元素都会成为“行内块”元素,如果不设定宽高,它会随着内容的变化而自适应宽高(不像 div 一个元素会占一行),也可以自定义宽高(span 等无法设置宽高)。还有上文提到的清除浮动所用到的 overflow: auto; 也是为了触发 BFC。

这里需要提醒一下,inline-block 可能会使相邻的元素之间产生间隙,因为浏览器会将换行符合成空白符,所以除非它们写在一行,或者可以给它们的父元素设置 font-size: 0;,再单独给子元素设置字体大小。

BFC 的规则

  • BFC 就是页面中的一个隔离的独立容器,容器里的标签不会影响到外部标签
  • BFC 就是一个块级元素,块级元素会在垂直方向一个接一个的排列
  • BFC 内的元素按正常流排列(可能外边距塌陷),元素之间的间隙由元素的外边距控制(不会发生外边距塌陷)。
  • 计算 BFC 的高度需包括 BFC 内浮动(float)子元素的高度(只有通过 float 脱离文档流的元素高度会计算在内,position: absolute; 等其他方式的不会)。

举个🌰。以下的 #box 高度为 120px,但如果去掉 display: inline-block;,高度就是 100px(虽然它们在页面上的表现形式看起来一样

<div id="box" style="display: inline-block;">
  <div style="height: 100px;">这是内容</div>
  <button style="float: left; height: 20px">点我~</button>
</div>

参考:《面试官:请说说什么是BFC?大白话讲清楚》

出现 flex 和 grid 之后,可以不用 float 强行让元素脱离文档流进行布局,所以已不用考虑清除浮动了,让 float 回归它原本的职能——做图文混排的效果叭~

image.png

其他小芝士

关于 font-weight

只有字体本身支持才能设置 font-weight 为具体数值,有些可能只支持 normalbold,所以设置数值可能会无效。

关于 line-height

行高 line-height 用于设置多行文本的间距。如果不写实际像素,如 1.5 即字体高度的 1.5 倍。

line-height 也常用于单行内容垂直居中,当 line-height 等于容器 content 的高度时,容器内的元素会垂直居中。