6.3 盒子模型最佳实践
6.3.1 盒子尺寸类型box-sizing
1、border-box基础
提问。width属性值一定表示内容宽度吗?不是。
box-sizing默认值是content-box,此时width表示内容宽度,height表示内容高度。
当box-sizing = content-box:
width属性值 = 内容区宽度
当box-sizing属性值是border-box时,此时width表示包含内容区+padding+border的宽度,height同理。两种模式下,width都不包括margin区域。
当box-sizing = border-box:
width属性值= 内容区宽度 + padding-left + padding-right + border-left + border-right
content-box与border-box的字面意思。content-box表示:宽度width指content区宽度;border-box表示:宽度width指包含border的宽度,也包含padding与content。
现在将最开始的示例转化成border-box时,并保持页面效果相同,width与height需要进行相应计算。width=220+(20+5)*2=270;height=30+(20+5)*2=80。
转换后代码
div {
box-sizing: border-box;
width: 270px; /*原值220*/
height: 80px; /*原值30*/
padding: 20px;
border: 5px solid #0aaa76;
margin: 10px;
}
查看盒子模型,各值与之前完全相同。
2、border-box的优点
两种尺寸类型能够实现相同效果,width值进行相应换算即可。border-box甚至似乎更麻烦:为保证内容宽度还需计算width值,而content-box直接设置就可以。
实际项目的常见场景:前提条件是元素含border与padding的宽度不变,要调整padding或border。
(1)content-box时 ,width=220px,padding=20px,border=5px。需求:要求padding改成30px。实现:则需要改动两项数值:padding调整、width同时调整成200px。因为padding变大,内容区相应变小。
(2)border-box时,width=270px,padding=20px,border=20px。需求:padding需改成30px。实现:只需要改动一项数值:padding调整,width无需改动,内容区宽度自动变小。
这类需求场景下,border-box时设置项与调整值更加简单:设置以含border的尺寸设置,调整时无需调整它。所以实际项目会设置所有元素的box-sizing值border-box。
3、全局统一设置border-box
box-sizing默认值。box-sizing默认值content-box,大多数标签没有重新设置;部分标签设置border-box,包括button、select、table,而input、textarea还是content-box。总之,标签默认设置并不统一。
实际项目通常设置所有元素统一采用border-box。虽然content-box是box-sizing的初始默认值,但实际应用border-box已成为事实标准。这也是CSS设计box-sizing初始值的一个缺陷,w3c官方承认这个设计缺陷。
border-box的全局统一设置代码
*,*::before,*::after{box-sizing: border-box;}
*表示匹配所有元素,因为*不能匹配到伪元素::before与::after,所以补上。
6.3.2 margin实现块容器水平对齐
margin水平auto值实现子div(子块容器)在父div(父块容器)的水平对齐。
margin水平对齐原理示意图
当子div没有设置width,子div会占满父div的宽度,无论父div是否设置宽度;当子div设置width,则父div内部的右侧会有剩余空间,上图2蓝色斜线区域所示,子div属于左对齐;设置子div的margin-left: auto与margin-right: auto表示左右margin值平分剩余空间,如上图3所示。最终实现子div的水平居中;仅设置子div的margin-left: auto表示左边margin值占满剩余空间,实现右对齐。
初始代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小步教程</title>
<style>
.div1{
width: 400px;
height: 50px;
background-color: #0aaa76;
}
.div2{
width: 200px;
background-color: #ed7d31;
}
</style>
</head>
<body>
<div class="div1">
<div class="div2">小步教程 xiaobuteach.com</div>
</div>
</body>
</html>
运行效果
(1)子div在父div里右对齐
.div2{
margin-left: auto;
}
运行效果
查看盒子,margin-left计算值为100px。
(2)子div在父div里水平居中
.div2{
margin-left: auto;
margin-right: auto;
}
运行效果
开发者工具查看盒子左右margin值各50px。
上述写法是原子属性写法,通常使用复合属性margin写法
.div2{
margin: 0 auto;
}
margin-top与margin-bottom此处设为0,可根据需求调整具体值。
上述对齐的前提条件。子div必须设置有宽度。如果没有设置宽度,它本身就会占满父div,导致父元素没有剩余水平空白,设置auto值也就没有意义。
6.3.3 margin实现子div宽度超出
margin水平负值实现子div宽度超出。盒子模型里,width/height、padding、border三者不能为负值,margin可以使用负值。
margin-left正值表示元素右移。margin-left负值不仅表示元素左移,还有一层含义:内容区宽度相应变大,从而实现子div宽度超出父元素宽度。这种场景通常不设置子div的宽度。margin负值让内容区变大的这种用法只适用于水平方向,不适用于垂直方向。
初始代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小步教程</title>
<style>
body{
padding: 20px 50px;
}
.div1{
width: 300px;
height: 50px;
background-color: #0aaa76;
}
.div2{
background-color: #ed7d31;
}
/* .div2{
margin: -10px -50px;
} */
</style>
</head>
<body>
<div class="div1">
<div class="div2">小步教程 xiaobuteach.com</div>
</div>
</body>
</html>
运行效果
查看div2盒子模型
现设置div2的margin设为负值(取消上述代码注释),运行效果如下。
内容宽度变宽,高度不变。开发者工具查看div2盒子。内容区宽度从300变为400,高度不变,与显示效果一致。