CSS盒子模型

213 阅读8分钟

CSS盒模型

盒子Box

Box是CSS布局的对象和基本单位,一个页面由很多个Box组成;

Box的类型,由元素的类型和display属性决定;

不同类型的Box,会参与不同的Formatting Context,因此Box内的元素会以不同的方式渲染;

image.png

标准模型 与 IE模型

标准W3C盒子的宽度为width = content内容区域

IE盒子的宽度为 width = conetent内容区域 + border + padding

标准盒子与IE盒子的设置是box-sizing属性:

标准盒子:box-sizing: content-box;

IE盒子:box-sizing: border-box;

所以由上面的知识点可以知道,宽度相同的盒子,标准盒子的width要比IE盒子的大;对比下图可一清二楚:

image.png

image.png

顺便提一下,chrome的box-sizing值是content-box;

BFC

块级格式化上下文(Block Fromatting Context,BFC),指一个 隔离的独立的块级渲染区域,是 Web 页面的可视化 CSS 渲染的一部分,是布局过程中生成块级盒子的区域,也是 浮动元素 与其他元素的交互限定区域。

注意:一个 BFC 的范围包含创建该上下文的所有子元素,但 不包括 创建了新 BFC 的子元素的内部元素。这从另一个角度说明,一个元素不能同时存在于两个 BFC 中。因为如果一个元素能够同时处于两个 BFC 中,那么就意味着这个元素能与两个 BFC 中的元素发生作用,就违反了 BFC 的 隔离作用

创建BFC的方法:

1、float部位none;

2、position不为static或者relative;

3、display为table

4、overflow部位visible;

运用场景:

1、外边距崩塌问题:

两个相邻盒子有反方向的外边距,会在垂直方向上产生上下边距合并的效果: image.png 如两个外边距都为30的盒子,他们之间的距离并不是60,而是30;

解决方法:给任意盒子加个父元素,并给其父元素加上任意创建BFC的条件;

image.png

2、另外还有清除浮动、浮动元素造成父元素的塌陷等问题,都可以利用BFC解决;

IFC

内联格式化上下文(Inline Formatting Context),是用于 布局内联元素 盒子的一块 渲染区域

形成条件: 块级元素中仅包含内联级别元素;

布局规则:

1、子元素水平方向横向排列,并且垂直方向起点为元素顶部。

2、子元素只计算横向样式空间,padding、border、margin在垂直方向上的样式空间不会被计算

3、在垂直方向上,子元素会以不同形式来对齐vertical-align

(例如:给高度最大的子元素设置vertical-align: 可以实现其他元素垂直居中)

4、能把在一行上的框都完全包含进去的一个矩形区域,被称为该行的行框(line box)。行框的宽度是由包含块(containing box)和与其中的浮动来决定。

5、IFC中的“line box”一般左右边贴紧其包含块,但float元素会优先排列。

6、IFC中的“line box”高度由 CSS 行高计算规则来确定,同个IFC下的多个line box高度可能会不同。

7、当 inline-level boxes的总宽度少于包含它们的line box时,其水平渲染规则由text-align 属性值来决定。

(例如,利用text-align实现多元素水平居中)

8、当一个“inline box”超过父元素的宽度时,它会被分割成多个boxes,这些 boxes 分布在多个“line box”中。如果子元素未设置强制换行的情况下,“inline box”将不可被分割,将会溢出父元素。

举例场景:

垂直间距不生效

如,在IFC中,给子元素加上margin值,只有左右边距生效,上下并没有生效,这就符合了第二条规则;

image.png

FFC 与 GFC

FFC

flex是flexible box的缩写,一般称之为弹性盒模型。
flex布局提供一种更加有效的方式来进行容器内的项目布局,以适应各种类型的显示设备和各种尺寸的屏幕,使用Flex box布局实际上就是声明创建了自适应格式上下文(Flex Formatting Context)

使用flex布局不得不提一个重要的属性flex: 1;

这是一个简写属性,由flex-grow,flex-shrink,flex-basis组成,默认值为0 1 auto

这里对flex-basis深究一下:

flex-basis的尺寸是作用在content-box上的,这个和width属性是一样的;而且flex-basis的优先级比width大,也就是同时设置了这两个,浏览器是优先展示flex-basis;

image.png

在content-box上: image.png 在border-box上: image.png

再看看zhangxinxu大佬的一句话,真的学到了!! image.png

再来看看width与flex-basis表现不同的情况: image.png image.png 可以看到当content内容超出时,flex-basis是按照content的最小内容宽度显示,而width是限制死的,字符直接溢出容器;

其实还有很多更细节的地方,这里就不一一探究了,但是有一个极其重要的原则: flex-basis数值属性值和width数值属性值不要同时使用,Flex布局中,除非万不得已,否则没有使用width属性的理由,请使用flex-basis代替。

flex一个问题:

有一个flex布局的盒子,其中子元素box1固定宽度,另一个子元素box2自由伸缩放,box2中有个p元素;

<style>
    .box1 {
      width: 100px;
      height: 100%;
      background-color: aqua;
    }
    .box2 {
      flex: 1;
      background-color: rgba(255, 145, 0, 0.89);
    }
    .box-wrap {
      display: flex;
      // width: 500px;  后面再加上
      height: 500px
    }
    p {
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
    }
</style>

  <div class="box-wrap">
    <div class="box1">box1</div>
    <div class="box2">
      <p>
        Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
      </p>
    </div>
  </div>

Then...box2把父盒子撑开的同时,把兄弟元素box1也挤得变形;

image.png

image.png

原因是:box2中的p元素装有长文本,内容套多导致父盒子被撑开;

解决方法: box2(也就是被撑开的元素)加上属性width: 0;

为什么能解决:

flex-basis 属性下的最小尺寸是由内容决定的,而 width 属性下的最小尺寸是由 width 属性的计算值决定的。

按我的理解是:

1、在flex-basiswidth的共同作用下,首先flex-basis的优先级是大于width的,所以在的正常宽度内(父盒子不被撑开或者子盒子的宽度大于内容宽度),是先按flex-basis的默认值0%展示的;

2、但是当内容宽度大于正常宽度时,就需要按照width的计算值来算,比如我给父盒子加上width: 500px,由于box1为100px,所以box2在设置width时在400px的范围内是正常的;但是如果width设置超过了400px,box2首先会挤压box1,然后当box1被挤压到最小内容宽度时,会撑开父盒子进行增长;

那么如果说box2不设置宽度的话,那么其宽度就由内容宽度决定,所以父盒子会被撑开;其次,设置width后,则按照上面理解的第二条,width: 0则不会超出父盒子,所以box2最大也就是父盒子的宽度 - box1.width

flex知识点2 在W3C的文档中,flex-basis 除了能接受 autocontent等值外,还能接受 与widthheight 属性相同的值,并且解析方式也相同。就是说 height 怎么解析 0px0%flex-basis 也这么解析。所以一般情况下,这2个值对 flex-basis 而言,在浏览器上的表现效果应该都是一样的;但是:

如果一个元素的 flex-basis属性 的值为百分数,且它父级元素(flex容器)在主轴方向上的尺寸没有被显式设置,此时 flex-basis 的值会被解析为 content。即此种情况下,0% 呈现的结果会与 0px 不同

通过查阅文档,知道W3C对于flex-basis的解析规则经历了0px > 0% > 0px的变化,但是在浏览器中只有0px > 0%,原因是会有兼容性问题。现在已有很多网页都利用了 flex 属性的这个特性来开发。如果简写语法里 flex-basis 的解析从 0% 变为 0px 会导致部分情况下flex容器塌陷,致使很多网页异常;

可以以下例子更直观的看到两者的区别:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .box-container {
      /* 没有设置明确height或者height为auto都会导致塌陷 */
      display: flex;
      flex-direction: column;
      align-items: center;
    }

    .box-wrap {
      flex-grow: 1;
      flex-shrink: 1;
      padding: 5px;
      margin: 5px;
      overflow: hidden;
      background-color: aqua;
    }

    .box {
      width: 300px;
      height: 300px;
      background-color: rgba(255, 145, 0, 0.89);
    }

    .basis-0-pct {
      flex-basis: 0%;
    }

    .basis-0-px {
      flex-basis: 0;
    }
  </style>
</head>
<body>
  <div class="box-container">
    <p>flex: 0%的盒子</p>
    <div class="box-wrap basis-0-pct">
      <div class="box"></div>
    </div>
  </div>
  <div class="box-container">
    <p>flex: 0的盒子</p>
    <div class="box-wrap basis-0-px">
      <div class="box"></div>
    </div>
  </div>
</body>
</html>

image.png

flex: auto 与 flex: 1; flex: 0 与 flex: none;的区别

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>学习</title>
    <style>
      .box-wrap {
        display: flex;
        /* 为了方便看效果,flex: 0与flex: none会加上该属性 */
        flex-direction: column;
        width: 800px;
        margin: 100px auto;
      }
      .item {
        margin: 10px;
        background-color: aquamarine;
      }
      /* 不断变化该属性值进行测试 */
      .flex-type {
        flex: 1;
      }
    </style>
  </head>

  <body>
    <div class="box-wrap">
      <div class="item flex-type">上面代码使用useEffect来进行数据的转化,效率很低。其实并不需要使用useEffect。当某些值可以从现有的props或state中计算出来时,不要把它放在状态中,在渲染期间计算它</div>
      <div class="item flex-type">上面代码使用useEffect来进行数据的转化,效率很低。其实并不需要使用useEffect。当某些值可以从现有的props或state中计算出来时,</div>
      <div class="item flex-type">上面代码使用useEffect来进行数据的转化,效率很低。其实并不需要使用useEffect。</div>
      <div class="item flex-type">上面代码使用useEffect来进行数据的转化,效率很低。</div>
    </div>
  </body>
</html>

flex: 1; image.png flex: auto; image.png

felx: 1是平分空间,flex: auto是根据内容大小来分,不是均分;

两者的差别为flex-basis: 0%/auto

flex: 0:

image.png

flex: none;

image.png

flex: 0flex-grow: 0; flex-shrik: 1; flex-basis: 0%

flex: noneflex-grow: 0; flex-shrik: 0; flex-basis: auto

flex: 0 不可扩大,可缩小,表现形式为最小内容宽度; 而flex: none 不可扩大,不可缩小,内容本身的宽度是多少就是多少;

GFC

GFC即网格布局格式化上下文(Grids Formatting Context),目前使用还比较少,届时再回来补充......

另外,再补充一点对于display: none, overflow: hidden, visibility: hidden之间的区别

1、dispaly: none: 隐藏元素,不占据空间;会产生回流与重绘;

2、overflow: hidden: 超出的元素部分隐藏且不占据空间;

3、visibility: hidden: 隐藏元素,但占据空间;只产生重绘