6.3 盒子模型最佳实践


6.3.1 盒子尺寸类型box-sizing

1、border-box基础

提问。width属性值一定表示内容宽度吗?不是。

box-sizing默认值是content-box,此时width表示内容宽度,height表示内容高度。

img

当box-sizing = content-box:
width属性值 = 内容区宽度

当box-sizing属性值是border-box时,此时width表示包含内容区+padding+border的宽度,height同理。两种模式下,width都不包括margin区域。

img

当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;
        }

查看盒子模型,各值与之前完全相同。

img


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水平对齐原理示意图

img

当子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>

运行效果

img

(1)子div在父div里右对齐

        .div2{
            margin-left: auto;
        }

运行效果

img

查看盒子,margin-left计算值为100px。

img

(2)子div在父div里水平居中

        .div2{
            margin-left: auto;
            margin-right: auto;
        }

运行效果

img

开发者工具查看盒子左右margin值各50px。

img

上述写法是原子属性写法,通常使用复合属性margin写法

        .div2{
            margin: 0 auto;
        }

margin-top与margin-bottom此处设为0,可根据需求调整具体值。

上述对齐的前提条件。子div必须设置有宽度。如果没有设置宽度,它本身就会占满父div,导致父元素没有剩余水平空白,设置auto值也就没有意义。

img


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>

运行效果

img

查看div2盒子模型

img

现设置div2的margin设为负值(取消上述代码注释),运行效果如下。

img

内容宽度变宽,高度不变。开发者工具查看div2盒子。内容区宽度从300变为400,高度不变,与显示效果一致。

img