• CSS 正常流


    正常流正常在哪里?

    很多人会问。

    我觉得感性的理解是很正常的。。。只不过如果我们从严苛的 CSS 标准角度去理解正常流,规定排版的算法,就需要引入那些复杂的概念,就变得常人难以理解不正常了。

    我们可以用一句话来描述正常流的排版行为,那就是:依次排列,排不下了换行。

    float 就不说了,前面有文章写过,看完以后基本就能对 float 是什么很了解。

    盒与文字是如何混合排版的 vertical-align 也不说了。

    margin 折叠是很多人非常不理解的一种设计,但是实际上我们可以把 margin 理解为“一个元素规定了自身周围至少需要的空间”,这样,我们就非常容易理解为什么 margin 需要折叠了。后面会专门写篇文章看什么是 margin 折叠。

    正常流的原理

    在 CSS 标准中,规定了如何排布每一个文字或者盒的算法,这个算法依赖一个排版的“当前状态”,CSS 把这个当前状态称为“格式化上下文(formatting context)”。

    BFC----IFC

    我们可以认为排版过程是这样的:

    • 格式化上下文 + 盒 / 文字 = 位置
    • formatting context + boxes/charater = positions

    我们需要排版的盒,是分为块级盒和行内级盒的,所以排版需要分别为它们规定了块级格式化上下文和行内级格式化上下文。

    块级格式化上下文顺次排列元素:

    a5e1b9a77d9745499f96d25cf0a0dbe7

    行内级格式化上下文顺次排列元素:

    1ced4fa809b30343df45e559cf0c08cf

    当我们要把正常流中的一个盒或者文字排版,需要分成三种情况处理。

    • 当遇到块级盒:排入块级格式化上下文。
    • 当遇到行内级盒或者文字:首先尝试排入行内级格式化上下文,如果排不下,那么创建一个行盒,先将行盒排版(行盒是块级,所以到第一种情况),行盒会创建一个行内级格式化上下文。
    • 遇到 float 盒:把盒的顶部跟当前行内级上下文上边缘对齐,然后根据 float 的方向把盒的对应边缘对到块级格式化上下文的边缘,之后重排当前行盒。

    我们以上讲的都是一个块级格式化上下文中的排版规则,实际上,页面中的布局没有那么简单,一些元素会在其内部创建新的块级格式化上下文,这些元素有:

    1. 浮动元素

    2. 绝对定位元素

    3. 非块级但仍能包含块级元素的容器(如 inline-blocks, table-cells, table-captions)

    4. 块级的能包含块级元素的容器,且属性 overflow 不为 visible

      设置了overflow,自身为块级,但是块级格式化上下文和外部的块级格式化上下文发生了融合,overflow:hidden 了,从排版的角度就是完全不存在的。

    正常流的使用技巧

    1. 等分布局问题

      横向等分布局是一个很常见的需求,按照一般的思路,我们可以使用百分比宽度来解决,我们参考以下代码:

      <div class="outer">
          <div class="inner"></div>
          <div class="inner"></div>
          <div class="inner"></div>
      </div>
      .inner {
          33.33%;
          height:300px;
          display:inline-block;
          outline:solid 1px blue;
      }
      

      但是这段代码执行之后,效果跟我们预期不同,我们可以发现,每个 div 并非紧挨,中间有空白,这是因为我们为了代码格式加入的换行和空格被 HTML 当作空格文本,跟 inline 盒混排了的缘故。

      解决方案是修改 HTML 代码,去掉空格和换行:

      <div class="outer"><div class="inner"></div><div class="inner"></div><div class="inner"></div></div>
      

      但是这样做影响了源代码的可读性,一个变通的方案是,改变 outer 中的字号为 0。

      .inner {
          33.33%;
          height:300px;
          display:inline-block;
          outline:solid 1px blue;
          font-size:30px;
      }
      .outer {
          font-size:0;
      }
      

      在某些浏览器中,因为像素计算精度问题,还是会出现换行,我们给 outer 添加一个特定宽度:

      .inner {
          33.33%;
          height:300px;
          display:inline-block;
          outline:solid 1px blue;
      }
      .outer {
          101px
      }
      

      这个代码在某些旧版本浏览器中会出现换行。为了保险起见,我们给最后一个 div 加上一个负的右 margin

      .outer {
          101px
      }
      
      .inner {
          33.33%;
          height:300px;
          display:inline-block;
          outline:solid 1px blue;
      }
      
      .inner:last-child {
          margin-right:-5px;
      }
      

      这样就可以解决旧版本浏览器的问题了。除了使用 inline-block,float 也可以实现类似的效果,但是 float 元素只能做顶对齐,不如 inline-block 灵活。

    2. 自适应宽

      我们再来说说自适应宽。在 IE6 统治浏览器市场的旧时代,自适应宽(一个元素固定宽度,另一个元素填满父容器剩余宽度)是个经典的布局问题,我们现在就看一下如何使用正常流来解决。

      <div class="outer">
          <div class="fixed"></div>
          <div class="auto"></div>
      </div>
      <style>
      .fixed {
          200px;
      }
      .fixed, .auto {
          height:300px;
          outline:solid 1px blue;
      }
      </style>
      

      这里 fixed 这个 div 宽度已经被指定好,我们需要添加 css 代码尝试让.auto 填满剩余宽度。

      使用正常流解决这个问题的思路是,利用负 margin:

      .fixed {
          display:inline-block;
          vertical-align:top;
      }
      .auto {
          margin-left:-200px;
          100%;
          display:inline-block;
          vertical-align:top;
      }
      

      但是,这样做会导致 auto 中的内容位置不对,所以我们还需要使用 padding 把内容挤出来,最终完整代码如下:

      .fixed {
          display:inline-block;
          vertical-align:top;
      }
      .auto {
          margin-left:-200px;
          padding-left:200px;
          box-sizing:border-box;
          100%;
          display:inline-block;
          vertical-align:top;
      }
      

      这样就给 auto 添加了 padding-left 和 box-sizing 两个属性。

      总的来说,正常流布局主要是使用 inline-block 来作为内容的容器,利用块级格式化上下文的纵向排布和行内级格式化上下文的横向排布来完成布局的,我们需要根据需求的横向和纵向排布要求,来选择元素的 display 属性。

    用 JavaScript 写一个仅包含 inline-block 的正常流布局算法

    
    
  • 相关阅读:
    git如何忽略特殊文件
    一文了解H5照片上传过程
    Vue组件通信方式(8种)
    H5 拍照图片旋转、压缩和上传
    Chrome插件推荐
    高效开发之使用Cmder替换cmd
    使用git配置ssh的文章推荐
    360极速浏览器如何默认设置必应搜索引擎
    notepad 多文档切换
    centos下kill、killall、pkill命令区别
  • 原文地址:https://www.cnblogs.com/ssaylo/p/13224603.html
Copyright © 2020-2023  润新知