【CSS】- 盒模型

216 阅读7分钟

盒模型可是 CSS 的重中之重,不理解这个,你的页面可能就会在视觉上出现各种“百思不得其解”现象,这篇文章可以带你了解什么是盒模型、盒模型的基本应用场景

盒模型

盒模型(box model)定义了页面上元素的表现形式,每个元素都将以“盒子”的形式显示在页面上。

盒模型分为 Block Box (块级元素)和 Inline Box(行内元素);一个盒子,从外到里包括了:margin(外边距)、border(边框)、padding(内边距)、content(内容)
image.png

标准盒模型

box-sizing属性定义了浏览器如何计算一个元素的总宽度和总高度。

在标准盒模型(box-sizing:content-box)中,如果给盒子设置 width height,实际设置的是 content box 的高度和宽度,也就是对一个元素所设置的 widthheight 只会应用到这个元素的内容区(content 部分)

如果这个元素有任何的 border padding ,渲染到 HTML 页面上时,盒子的 width 和 height 除了要包含 content,还要额外加上你设置的 marginpaddingborder
image.png

例如,当你定义了一个宽度与父容器相同的子元素,运行后你会发现子元素看上去溢出了父容器——父容器装不下子元素了。这就产生了一个问题——盒子的实际大小超过了你设定的大小:

#container{
    width: 300px;
    border: 5px solid rgb(100, 100, 100);
}

#container div{
    width: 300px;
    height:90px;
    border: 10px solid rgb(86, 134, 189);
    font-size: 24px;
}
<div id="container">
    <div id="b1">子元素</div>
    <div id="b2">子元素</div>
    <div id="b3">子元素</div>
</div>

image.png

IE 盒模型

像上面子元素溢出父容器的情况,通过设置box-sizing:border-box就能解决,这表示启用 IE 盒模型。
在 IE 盒模型中,盒子的大小为 content + border + padding,这样,你设置的盒子为 100px,即使你再加上 5px 的 border 和 10px 的 padding,盒子的实际大小就会是你原本设置的 100px,这样其实更符合直觉,且不需要手动计算盒子的大小

我们让父容器的宽度为 300px ,边框为 5px ,然后启用 IE 盒模型:

#container{
    width: 300px;
    box-sizing: border-box;
    border: 5px solid rgb(100, 100, 100);
}

#container div{
    width: 290px; // 这里要减去两边的父容器的 border
    box-sizing: border-box;
    height:90px;
    border: 10px solid rgb(86, 134, 189);
    font-size: 24px;
}

image.png

块级盒子

首先,我们来定义一个父元素和三个子元素:

<style>
        #container{
            border: 5px solid rgb(100, 100, 100);
            padding: 30px;
        }

        #container div{
            height: 80px;
            border: 10px solid rgb(86, 134, 189);
            font-size: 22px;
        }
</style>

<body>
    <div id="container">
        <div id="b1">块级盒子 1</div>
        <div id="b2">块级盒子 2</div>
        <div id="b3">块级盒子 3</div>
    </div>
</body>

image.png
块级元素的特性如下:

  • 元素的宽度会铺满父容器
  • 元素会自动换行,每个元素独占一行
  • width height 属性生效
  • padding、margin、border 会将其他元素从当前元素周围“推开”

常见的块级元素有:<div><p><ul><ol><h1> ~ <h6>

行内盒子

<style>
        #container{
            height: 300px;
            border: 5px solid rgb(100, 100, 100);
            padding: 30px;
        }

        #container div{
            display: inline;
            border: 10px solid rgb(86, 134, 189);
            font-size: 22px;
        }
</style>

<body>
    <h1>行内元素</h1>
    <div id="container">
        <div id="b1">行内盒子 1</div>
        <div id="b2">行内盒子 2</div>
        <div id="b3">行内盒子 3</div>
    </div>
</body>

image.png
行内元素的特性如下:

  • 元素不会自动换行,除非溢出父容器才会换到下一行
  • width height 属性不生效
  • 垂直方向的 padding 、margin、border 会生效,但是不会把其他处于 inline-block 状态的元素推开
  • 水平方向的padding 、margin、border 会生效,且会把其他处于inline-block 状态的元素推开。

常见的行内元素有:<a> <span><i><b>

元素显示类型

display属性定义了元素在文档流中显示的性质,默认情况下,div 元素:display:blockspan元素:display:inline

display 属性有以下可选值:

  • block:块级元素 ,会独占一行,默认带有换行符
  • inline:行内元素,不会独占一行,如果一行排不下才会换行
  • inline-block:行内块元素,会以 inline 的方式排列在父容器中,但同时具有块级元素的特点,例如可以设置 widthheight属性并生效
  • none:设置元素为不显示,且元素也不会存在于DOM节点中
  • flex:设置元素内部的布局为 flex 布局
  • grid:设置元素内部的布局为 grid 布局

外边距折叠

外边距折叠在 CSS 给元素布局的过程中非常常见,有必要弄清楚。首先,外边距折叠指的是:盒子的上外边距(margin-top)和下外边距(margin-bottom)有时合并(折叠)为单个边距,其大小为单个边距的最大值(或如果它们相等,则仅为其中一个)

下面的情况会形成外边距重叠:

  1. 相邻的两个同层级元素
<style>

        .container {
            border: 3px solid grey;
        }

        .top {
            background: red;
            width: 500px;
            height: 100px;
            margin: 20px; // 较小外边距
            border: 2px solid black;
        }

        .bottom {
            background: green;
            margin: 50px; // 较大外边距
            width: 500px;
            height: 100px;
            border: 2px solid black;
        }
</style>

<body>
    <div class='container'>
        <div class='top'>盒子一</div>
        <div class='bottom'>盒子二</div>
    </div>
</body>

image.png

  1. 没有内容将父元素和后代元素分开时

如果一个父元素,没有borderpadding、行内内容,也没有开启 BFC 来分开一个块级元素的上边距margin-top 与其后代块级元素的上边距margin-top;或者,没有borderpadding、行内内容、heightmin-heightmax-height 来分开一个块级元素的下边距margin-bottom与其后代块元素的下边距margin-bottom,就会出现父元素和后代块元素外边框重叠,重叠部分最终会溢出到父级块元素外面

<style>
        .container {
            background-color: grey;
        }

        .top {
            background: red;
            width: 500px;
            height: 100px;
            margin: 50px;
            border: 2px solid black;
        }

        .bottom {
            background: green;
            margin: 50px;
            width: 500px;
            height: 100px;
            border: 2px solid black;
        }
</style>

<body>
    <div class='container'>
        <div class='top'>盒子一</div>
        <div class='bottom'>盒子二</div>
    </div>
</body>

image.png

BFC

BFC 指的是块级格式化上下文(Block Formatting Context )。BFC 是 CSS2.1 规范中的一个概念,它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。

具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性 。通俗一点来讲,可以把 BFC 理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。

应用场景

高度塌陷

通常情况下,如果一个元素浮动,那么这个元素的父容器的高度,就不会再包括它本身的高度了,也就是高度塌陷

<style>
    body{
        padding: 50px;
    }
  
    .left {
        background: red;
        opacity: 0.7;
        border: 3px solid black;
        width: 200px;
        height: 200px;
        float: left;
    }
  
    .right {
        background: green;
        opacity: 0.7;
        border: 3px solid black;
        width: 400px;
        height: 100px;
    }
  
  	/* 父元素 */
    .container {
        background: grey;
        padding: 20px;
    }
</style>

<body>
    <div class='container'>
        <div class='left'> </div>
        <div class='right'> </div>
    </div>
</body>

image.png
可以看到,父元素的高度并没有将红色子元素的高度计算在内,因为红色子元素浮动了。父元素可以通过触发 BFC 来解决高度塌陷的问题:

  	/* 父元素 */
    .container {
        background: grey;
        padding: 20px;
      	overflow: hidden
    }

image.png

元素重叠

上面的例子中,红色子元素与绿色子元素发生了重叠,这是因为红色子元素float: left的原因,现在,我们需要避免绿色子元素发生重叠的话,可以触发它的 BFC:

.right {
    background: green;
    opacity: 0.7;
    border: 3px solid black;
    width: 400px;
    height: 100px;
    overflow: hidden; // 触发 BFC
}

image.png

外边距折叠

默认情况下,两个相邻元素的上下边距的值不是它们各自边距值的合,而是两者之间的最大值。

<style>
    body{
        padding: 50px;
    }
  
    .container {
        background: grey;
    }
  
    .top {
        background: red;
        height: 100px;
        margin: 50px;
        border: 2px solid black;
    }
  
    .bottom {
        background: green;
        margin: 50px;
        height: 100px;
        border: 2px solid black;
    }
</style>

<body>
    <div class='container'>
        <div class='top'> </div>
        <div class='bottom'> </div>
    </div>
</body>

image.png
可以看到,两个子元素的margin都是 50px,但是红色元素下边与绿色元素的上边的间隔距离,很明显不是直觉上认为的 50px+50px = 100px,这就是发生了外边距折叠。可以通过触发 BFC 来解决这个问题,我们需要给其中一个子元素再套上一个父元素,然后在这个父元素上面开启 BFC

 <style>
        body {
            padding: 50px;
        }

        .container {
            background: grey;
            overflow: hidden;
        }

        .top {
            background: red;
            height: 100px;
            margin: 50px;
            border: 2px solid black;
        }

        .bottom {
            background: green;
            margin: 50px;
            height: 100px;
            border: 2px solid black;
        }

        .bfc {
            overflow: hidden;
        }
</style>

<div class='container'>
    <div class="bfc">
        <div class='top'> </div>
    </div>
    <div class='bottom'> </div>
</div>

现在上下两个元素之间的边距就是它们的合啦
image.png

触发BFC

只要元素满足下面任一条件即可触发 BFC 特性:

  • 浮动元素:float属性除none以外的值
  • 绝对定位元素:position属性为absolutefixed
  • 元素的display属性为:inline-block、table-cell、flex、inline-flex、table-caption
  • overflow属性除了visible以外的值(hidden、auto、scroll)


元素层叠

z-index用来设置元素在z轴上面的堆叠顺序。z-index必须和定位元素position:absollute|relative|fixed一起使用,否则无效。

通常情况下,z-index的数值越高,层级就越高,但是也有特殊情况:

  1. 相同 z-index
    1. 如果两个元素都没有定位且发生位置重合现象,或者两个元素已定位且z-index相同发生且位置重合现象,那么按文档流顺序,后面的覆盖前面的。
    2. 如果两个元素都没有设置z-index,使用默认值;如果一个已定位,一个没有定位,那么定位元素覆盖未定位元素。
  2. 父子 z-index
    1. 如果父元素z-index有效,那么子元素无论是否设置z-index都和父元素一致,在父元素上方
    2. 如果父元素z-index失效(未定位或者使用默认值),那么已定位子元素的z-index设置生效

参考链接: