关于盒模型+flex+position属性的总结

821 阅读13分钟

给碌碌无为的自己, 留下一点痕迹, 证明曾经来过。

本文主要内容有以下几点:

  • 盒模型
  • 布局
    • float属性的引入
    • BFC介绍
    • Flex布局
    • 定位:postion属性。

盒模型

在CSS中,会把所有HTML标签当作一个"透明"的盒子来处理。所有的盒子会被划分为两类

  • 块级盒子
  • 内联盒子

块级盒子

块级盒子的特性:

  • 在网页上独占一行,所占据的宽度是父元素宽度的百分百
  • 块级盒子可独立设置宽高
  • 块级盒子的实际大小受到margin,border,padding的影响

盒模型的效果如下所示:

box_model.png

  • 从黑色边框到箭头所指的地方为外边距:由margin属性控制。影响的是盒子与盒子之间的距离。
  • 粉红色区域为内边距,由padding属性控制。控制的是内容区到border的距离。
  • 黑色为边框。由border属性控制。
  • content区域的大小由 width,height属性控制。

因此盒子的水平方向的大小为 margin-left +margin-right + width + border-left +border-right + padding-left + padding-right

盒子的垂直方向的大小为 margin-top + margin-bottom + height + border-top + border-bottom + padding-top + padding-bottom

内联盒子

内联盒子有如下特性

  • 在网页上不会独占一行,默认的情况下,盒子沿着内联方向依次排列
  • 不能设置宽高,大小完全由内容撑开
  • 垂直方向的margin和padding会被应用,但是不会把其他元素撑开
<style>
    .box2 {
        width: 100px;
        height: 100px;
        background-color: black;
        /* margin-top: 200px; */
    }
    span{
        margin-top: 100px;
        border: 1px solid red;
    }
    strong{
        padding-top: 100px;
        /* background-color: aqua; */
        border: 1px solid #555;
    }
</style>
<body>
    <div class="box2">
        我是块级盒子
    </div>
    <span>我是一个内联盒子被设置了 <code>margin-top:100px</code></span>
    <span>我是一个内联盒子被设置了 <code>margin-top:100px</code></span>
    <span>我是一个内联盒子被设置了 <code>margin-top:100px</code></span>
    <span>我是一个内联盒子被设置了 <code>margin-top:100px</code></span>
    <strong>我是一个内联盒子被设置了 <code>padding-top:100px</code></strong>
</body>

inline_model_margin_padding.png

打开调试器(F12)可以看到span元素的margin-top确实存在,但和box2之间并没有100px的间距,padding在垂直方向上也是如此

inline_model_margin_padding02.png

此时给span和strong分别添加margin-left: 20px; padding-left: 100px;

inline_model_margin_padding03.png

打开调试者窗口就可以看到如下信息

inline_margin_padding04.png

可以看到在水平方向的margin和padding都起了作用。

盒模型之间的相互转换

display属性可以切换盒子的外在变现形式,

display:block 可以将盒子的外在表现形式切换为块级元素

display:inline 可以将块级盒子切换为内联盒子

display:inline-block可以将盒子设置为处于块级盒子和内联盒子之间的中间态: 即可以设置宽高,且不会独占一行。

外边距重合问题

盒子和盒子之间的距离由margin属性控制,因此当相邻两个盒子设置了相对方向的margin 就会出现外边距重叠的问题

<style>
    .box1 {
        width: 200px;
        height: 200px;
        border: solid 1px #333;
        background-color: #696969;
        margin-bottom: 200px;
    }
    .box2 {
        width: 200px;
        height: 200px;
        border: solid 1px #333;
        background-color: red;
        margin-top: 100px;
    }
</style>
<body>
    <div class="box1"></div>
    <div class="box2"></div>
</body>

小记:上述盒模型的成立实在box-sizing:content-box;条件下成立,当box-sizing:border-box;时,也成立,只不过盒子的大小计算有差异。在这种情况下,width,height属性控制的是整个块级盒子的大小。内容区域的大小为:整个盒子的大小 - 相应的border和margin属性的值。

文档流

Normal Flow: 在默认情况下 HTML页面元素的布局方式是:块级元素从上到下排列,内联元素沿着内联方向水平排列。

浮动

float属性最初的引入是为了进行简单的布局,如首字下沉等。 默认排版如下:

首字下沉:

但是web开发人员在实际工作中发现,任何盒子都可以使用float。而float属性的使用也会导致其他问题。

float:left/right 当元素设置了这个属性时,该元素会脱离正常的文档流。显示效果会"高于"其他处于正常文档流的元素。浮动的元素在脱离正常文档流之后,在原本的文档流中将不占据位置。因此会导致如下情况的发生

  1. 父元素的高度丢失。
  2. 垂直方向的元素外边距塌陷
  1. 演示父元素高度丢失。

html代码结构:

<div class = "container">
    <div class="box"><div>
    <div class="box"><div>
<div>

css代码:

.container{
    border: 1px solid #333;
}
.box{
    width: 200px;
    height: 200px;
    border: solid 1px red;
    margin: 10px;
    background: #555;
}

效果如下

float_01.png

给box添加如下属性float:left;就可以看见两个元素均脱离了原文档流。导致container容器的高度丢失。

float_loss_height.png

  1. 外边距塌陷 [父子关系]
<style>
    .container {
        background-color: aqua;
        width: 300px;
        height: 300px;
    }
    .box {
        margin-top: 100px;
        width: 100px;
        height: 100px;
        background-color: #666;
    }
</style>
<body>
    <div class="container">
        <div class="box">
        </div>
    </div>
</body>

可以看到本应该是灰色的盒子距离大盒子的顶部100px,实际却是父元素向下塌陷了100px;

float导致父子元素的外边距塌陷.png

  1. 非兄弟元素之间的外边距重叠问题:
<head>
    <style>
        .container {
            /* display: flow-root; */
        }
        .box {
            margin-bottom: 100px;
            width: 100px;
            height: 100px;
            background-color: #666;
        }
​
        .box2 {
            width: 100px;
            height: 100px;
            background-color: black;
            margin-top: 200px;
        }
    </style>
</head><body>
    <div class="container">
        <div class="box">
        </div>
    </div>
    <div class="box2"></div>
</body>

包裹容器与同级元素之间的外边距重叠.png

BFC

Block Formatting Context:指块级盒子的布局过程中发生的区域,为浮动或者定位的元素开启一块块级区域。可以理解为一块单独的布局区域。简称BFC。开启一块包含浮动的布局或者消除外部布局的影响

在新开启的布局区域里面。会排除掉其他布局区域元素的影响。

作用:

  • 包含内部浮动:即创建包含浮动的BFC 如上面的演示父元素高度丢失的例子
  • 阻止外边距重叠
  • 排除外部浮动
  1. 包含内部浮动的作用演示:
  1. 父元素高度丢失的解决方法。

  • 利用clear属性。clear属性:消除浮动的影响
.container::after{
    content: "";
    display: table;
    clear: both;
}
  • 通过display:flow-root;开启bfc。

  1. 父子间的外边距塌陷也可通过display:flow-root;开启bfc。解决
  1. 阻止外边距重叠的作用演示

上述的例子3. 按照预期结果间距应该是100+200 = 300px;因为发生了重叠,因此在父元素上添加display:flow-root;属性。

解决方法就是给container开启BFC如display:float-root; 或者通过clean属性消除float元素的影响。

包裹元素消除外边距重叠.png

  1. 排除外部浮动

由于使用了float元素的会脱离原本的原本的位置,在其下的元素会向上移动。因此就会出现这种情况

<style>
    .box{
        background-color: aqua;
        margin: 10px;
        border: 2px solid #666;
        font-size: 28px;
        width: 60px;
        float: left;
        width: 200px;
        height: 150px;
    }
    .info{
        background-color: aquamarine;
        /* display: flow-root; */
    }
</style>
<div class="container">
    <div class="box"></div>
    <div class="info">
        <p >这是一段文字。。。</p>
    </div>
</div>

outter_float.png

因此为了消除 boxinfo 的影响 只需要在info上开启BFCC即可。即display:flow-root;

two_column_layout.png

除此之外还有一种情况

<style>
    .container{
          background-color: aquamarine;
    }
    .box{
        background-color: aqua;
        margin: 10px;
        border: 2px solid #666;
        font-size: 28px;
        float: left;
        width: 200px;
        height: 150px;
    }
</style>
<div class="container">
    <div class="box"></div>
    <p>这是一段很长的文字信息...很长很长很长。。。。。。。。</p>
</div>

此时的显示效果如下,因为box元素开启了float属性,导致其显示层级在p元素之上。因此p元素上衣,就出现了如下效果。

兄弟元素float的影响.png

为了消除这种影响。可以在container元素上添加display:flow-root;开启一个包含浮动的BFC布局

container开启BFC.png

Flex布局

开启flex之后的默认行为

如果说display:block/inline;属性改变了元素的外在表现形式。则display:flex;改变了元素内部的排列方式。

  • 在开启flex布局后,容器内的元素将会按照 主轴 (main axis) 和 交叉轴 (cross axis)的方向来排列元素。默认情况下

主轴从左到右,左边为起始方向,右边为终止方向。

交叉轴从上到下,交叉轴垂直于主轴方向。

display_flex.png

主轴的方向由flex-direction属性控制

flex-direction:

  • row: 默认 起始在做 终止在右
  • row-reverse:水平方向,起始在右,终止在左
  • column:从上到下 起始在上 终止在下
  • column-reverse 从下到上,起始在下,终止在上

默认值: flex-direction:row

flex_row_default.png

改变主轴方向为交叉轴方向:flex-direction:column

flex_direction_column.png

  • 在开启Flex的属性的元素中,默认全部元素在一行显示,呈一维状。可以通过flex-wrap 属性来改变元素是否换行排列

flex_wrap.png

确定flex-item的大小

在知晓了dispaly:flex的默认行为之后,就来确定flex容器元素的大小。

  • flex-basic
  • flex-grow
  • flex-shrink

eg3: 代码及效果如下

<style>
    .flex-container{
        display: flex;
        width: 500px;
        height: 200px;
        border: solid seagreen 1px;
    }

    .box1{
        background-color: aqua;
        width: 100px;
    }

    .box2{
        background-color: burlywood;
        width: 100px;

    }
    .box3{
        background-color: cadetblue;
        width: 100px;
    }
</style>
<body>
    <div class="flex-container">
        <div class="box1">1</div>
        <div class="box2">2</div>
        <div class="box3">3</div>
    </div>
</body>
  • flex-basic

默认情况下。flex-item元素会在交叉轴方向align-self:stretch; 拉伸至父容器的高度。

flex_item_default.png

box1,box2,box3都设置了width:100px; 于是乎空白区域的大小为 500 - 300 = 200px; 这片空白区域的大小可称为 available space

由于均设置了width:100px; 因此每一个item的大小就是100px,换言之。如果没有设置width属性,即flex-basic:auto;flex-basic的值采用元素内容尺寸。即元素content区域。

  • flex-grow

当flex-item的大小之后小于container容器时,为了达到内容填满容器的效果,可通过此属性控制u

在上面的例子中,用于还剩下200px的 available space。因此分别对box1,box2,box3 添加flex:5;flex:3;flex:2;

可以看到1,2,3 得到了不同程度的增大。如下图:

flex_item_grow.png

每个的大小分别为200px;160px;140px;计算方式为 原大小 +( 自己的flex-grow / 所有的flex-grow之和 ) * available space;

以box1为例子则:100px + (5/(2+3+5)) * 200 = 200px;box1的盒模型图如下

flex_grow_box1.png

  • flex-shrink

flex-grow 属性负责按比例扩大元素。当所有元素大小之和大于container的宽度之时。则 flex-shrink 负责按比例缩小元素。只不过available space不再是未填满的区域, 而是多出的空间。即 available space = 所有item之和 - container的值

将box1,box2,box3 的宽度都设置为200px 此时 available space = 600 - 500 = 100px;

分别给box1,box2,box3设置flex-shrink:5;flex-shrink:3;flex-shrink:2; 则效果图如下

flex_shrink.png

可以看到 box1 目前最小,缩小得最多。此时box1的大小为 200 - (5 / 10) * 100 = 150px; box1的盒模型图如下

flex_shrink_box1.png

注:通常 flex-grow flex-shrink flex-basic 这三个属性不会单独使用。通常简写为flex如:flex: 1, 1, auto; 则代表 flex-grow:1;flex-shrink:1;flex-basic:auto;

flex-item在flex容器中的分布和排列顺序

  1. 在开启display:flex之后,我们知道flex-item元素默认排在一行且不会换行。
  2. flex容器中的每一项在交叉轴方向得到拉伸,默认是flex容器的高度。

因此如何控制每一个 flex-item 在主轴或交叉轴的排列?

属性控制:

属性取值链接

  • justify-content: 控制主轴上所有flex项目的对齐
  • align-items: 控制交叉轴上所有项目的对齐
  • align-self: 控制交叉轴上的单个元素的对齐
  • align-content: 控制 "多条主轴"的flex项目交叉轴的对齐。

排列顺序:

有时候存在如下情况:

<style>
    .container{
        width: 600px;
        height: 400px;
        display: flex;
        justify-content: space-around;
    }
    .box{
        width: 100px;
        height: 100px;
        border: solid 1px red;
    }
</style>
<body>
    <div class="container">
        <div class="box">我是第一个元素但是我想在最后</div>
        <div class="box">我是第二个元素但是我想在最前面</div>
        <div class="box">我是第三个元素但是我想在第一个前面</div>
        <div class="box">我是最后一个但是我想在二三之间</div>
    </div>
</body>

此时的显示效果如下:

order_default.png

因此为了达到显示的效果可以通过order属性控制,order属性的值越小,就越靠近主轴的开始方向。

在CSS中添加如下规则。

.container :nth-child(1){
    order: 4;
}
.container :nth-child(2){
    order: 1;
}
.container :nth-child(3){
    order: 2;
}
.container :nth-child(4){
    order: 3;
}

此时显示效果如下:

order.png

定位 position

如果说flex布局在一定程度上规定了元素的大体的框架排列。则 position属性就相当于"微操"。即display:flex 在布局上相当于决定了一个人整体的面部,那么position 就相当于整个双眼皮这种微调。

  • position
  • 1.static 默认值,没有开启的定位
  • 2.relative 开启相对定位 参照位为元素在文档流中的位置。相对于自己以前的位置。

  • 特点:

    • 1.开启相对定位后,如果不设置偏移量,则元素不会发生任何变化

    • 2.offset 偏移量:改变元素的位置 开启定位后 通过下列几个值来设置偏移量 垂直方向

      • top:定位元素和定位位置上边的距离 从上往下压
      • bottom:定位元素和定位位置下边的距离 水平方向
      • left:定位元素和定位位置左边的距离
      • right:定位元素和定位位置右边的距离
    • 3.相对定位会提高元素的层级

    • 4.相对定位不会脱离文档流,不会改变元素的性质

.wrapper{

}
.box{
height: 100px;
width: 200px;
background-color: beige;
}
.relative-box{
width: 300px;
height: 200px;
background-color: aquamarine;
}
<body>
    <div class="wrapper">
        <div class="box">
            我是一个参照盒子
        </div>
        <div class="relative-box">
            我是相对定位 相对与原来的位置移动
        </div>
    </div>
</body>

此时两个盒子挨在一起如下图所示。 给.relative-box 添加position:relative;top:50px;

relative-default.png

可以看到两个盒子间间隔了50px;top:50px; 相当于有个在上面的力,这个力的大小导致盒子向下移动了50px的位置。

relative-top.png

  • 3.absolute 开启绝对定位 特点

    • 1.开启绝对定位后,不设置偏移量 元素的位置不会发生变化

    • 2.元素会从文档流中脱离

    • 3.绝对定位会改变元素的性质

    • 4.绝对定位会提升元素层级 参照物:绝对定位相对于其包含块进行定位的。 包含块是开启了定位的元素即非static元素 包含块containing block:

    • 1.绝对定位的包含块就是离他最近的开启了定位的祖先块元素

      • 1.如果所有的祖先元素都没有开启定位,则根元素就是他的包含块 html--初始包含块
<style>
    .wrapper{
        position: relative;
        width: 400px;
        height: 300px;
        background-color: #666;

    }
    .box{
        height: 100px;
        width: 200px;
        background-color: beige;

    }

    .absolute-box{
        /* position: absolute; */
        width: 300px;
        height: 200px;
        background-color: aquamarine;
        /* top: 0; */
    }
</style>
<div class="wrapper">
    <div class="box">
        我是一个参照盒子
    </div>
    <div class="absolute-box">
        我是绝对定位 相对于最近的开启定位的元素
    </div>
</div>

默认的显示效果如下

absolute_default.png

此时添加position:absolute可以发现元素表面上没有任何变化。添加top:0就可以看到参照盒子被遮住了!! 这就是因为开启绝对定位后,该元素脱离了文档流,导致显示层级高于的参照盒子。

absolute.png

此时可以通过z-index属性控制元素的显示, z-index只对开启了定位的元素起作用。z-index的值越大。显示的优先级就越高。

给参照盒子添加z-index:1; 就可以看到如下效果

position_index.png

  • 4.fixed 开启固定定位 特点

    • 1.一种特殊的绝对定位。永远参照于浏览器的视口进行定位。
    • 2.元素不会随着网页固定定位发生改变
<head>
    <style>
        .wrapper{
            position: relative;
            width: 400px;
            height: 2000px;
            background-color: blanchedalmond;
        }
        .fixed-box{
            position: fixed;
            bottom: 100px;
            background-color: aqua;
        }
    </style>
</head>
<body>
    <div class="wrapper">
        <div class="fixed-box">
            我是一个参照盒子 <br> <code>   position: fixed;   bottom: 100px;</code>
        </div>
    </div>
</body>
</html>

此时无论怎么滑动,他的位置都不会变。

fixed.png

  • 5.sticky :粘性定位可以被认为是相对定位和固定定位的混合。元素在跨越特定阈值前为相对定位,之后为固定定位。例如position:sticky;top:0px
<style>
    .wrapper{
        width: 400px;
        height: 2000px;
    }
    .box{
        background-color: red;
        width: 90%;
        margin: 5px;
        height: 30px;
    }
    .sticky-box{
        position: sticky;
        top: 0;
        background-color: aqua;
    }
</style>
<body>
    
    <div class="wrapper">
        <div class="box">1</div>
        <div class="box">2</div>
        <div class="sticky-box">
            我是一个参照盒子 <br> <code> position: sticky; top: 20px;</code>
        </div>
        <div class="box">3</div>
        <div class="box">4</div>
        <div class="box">5</div>
        <div class="box">6</div>
        <div class="box">7</div>
        <div class="box">8</div>
        <div class="box">9</div>
    </div>
</body>

默认效果是这样

sticky_default.png

当使用鼠标向下滑时:当开启position: sticky;的元素滑指与top的距离为指定的距离后,就不再继续滑动。

sticky.png

参考资料: