前一阵子遇到一个小问题,在同样的样式(主要是宽高边距之类的)条件下,DIV 在移动端和 PC 端的宽度不一样,排除了绝大多数样式的问题,但是有个比较陌生,就是 box-sinzing,其实经常看到,只不过没怎么注意过,连具体的值都不知道有哪些,在开发者工具里面试了一下,果然和这个样式有关,因此查了一些资料并记录一下。
盒子模型
首先,盒子模型大家都知道,W3C 标准的 Box Model 由四部分组成——content、padding、border、margin
Every box is composed of four parts (or areas), defined by their respective edges: the content edge, padding edge, border edge, and margin edge.
如果我们给一个应用了标准盒模型的 div 设置一个宽度,那么,实际上我们设置的是上文提到的 content 的宽度,也就是下图这个样子
- Element 空间高度 = content height + padding + border + margin
还有个不那么“标准”的盒模型,就是 IE6 以下(也就是处于 Quirks 怪异模式)的浏览器所使用的,在这种情况下:
- Element 空间宽度 = content Width + margin (Width 包含了元素内容宽度、边框宽度、内距宽度)
这个时候如果我们给 div 设置一个宽度,那就是为元素的内容 + 边框 + 内边距设置了一个总值,如图所示
上面张图片都使用以下这段代码
div {
width: 200px;
height: 100px;
margin: 40px;
padding: 20px;
border: 10px solid blue;
}
与 box-sizing 有什么关系
通过 box-sizing 这个样式我们可以改变这种宽度计算方式,它的属性值有两个:content-box 和 border-box。默认值为 content-box,也就是标准的盒子模型,此时的计算公式为
- width = 内容的宽度
- height = 内容的高度
另一个属性为 border-box,它的 width 和 height 属性包括内容,内边距和边框,但不包括外边距。看到这里相信大家都已经明白了,我们用了一个新的属性重现了一个不太“标准”的标准,被设置为 border-box 的元素在计算宽高时使用的就是 IE6 的模式。
我们为什么要开历史的“倒车”
其实也不能那么说,只是绕了一圈之后时间又证明了哪一种方式更合理而已,也并没有谁对谁错的问题,那么这种计算宽高的模式好在哪里呢?我们举个简单的例子
<div id="container">
<div id="header" class="content_box">
header
</div>
<div id="left" class="content_box">
left
</div>
<div id="right" class="content_box">
right
</div>
<div style="clear: both;"></div>
<div id="footer" class="content_box">
footer
</div>
</div>
.content_box {height: 48px;}
#container {
width: 480px;
background: yellow;
}
#left {
width: 120px;
background: red;
float: left;
}
#right {
width: 360px;
background: blue;
float: left;
}
这种左右布局的应用可以说十分广泛,并且看起来很直观且合理,但是如果我们随便在 left 或 right 中加 1px 的内边距或 border,整个布局就会被破坏,原因很好理解,按我们上面所说,现代浏览器默认是 content-box 模式,设定的宽度是内容的宽度,当我们增加了 padding 或者 border 的时候,left+right 就不再是 120+360=480 了,而是 120+360+1=481,由于容器的宽度不够,div 就会自动换到下一行,就变成了现在这个样子:
bootstrap 怎么解决的
说到这里,已经有人开始想了,为什么以前没有发现这个问题,我也是最近才遇到这种情况,因为 bootstrap 已经预先重置了默认的 box-sizing,而很多组件又是以 bootstrap 为基底来做文章,所以即使我们不知道 box-sizing 这一样式,很可能也已经熟悉了这种模式。
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
*:before,
*:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
另外,bootstrap 并不是在所有地方都用 border-box,在一些特定元素上还是使用 content-box
hr {
height: 0;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
input[type="checkbox"],
input[type="radio"] {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
控件的 box-sizing
当看到 bootstrap 对控件单独设置 box-sizing 时我产生一些疑问,控件的默认 box-sizing 难道不一样吗?事实证明确实不一样,以常见的 text 和 button 来说,text 默认就是 content-box,而 button 则是 border-box,这就不难理解为什么有时候我们给不同的控件设置同样的宽高却又无法对齐,这也是 box-sizing 在作祟。
注意甄别
不过对于这一样式也有分歧,所以不同的样式库使用 box-sizing 标准就不太相同,当我们引入了不同的库之后就要额外甄别这一问题,选择项目最适合的那种。
关于 padding 值不包含在 width 里面的问题,可能和 box-sizing 有关
box-sizing