How does flex-wrap work with align-self, align-items and align-content?(结合自身理翻译)

前言

  • 本人在回顾flex布局的语法时发现自己不理解align-items和align-content的区别
    • 仅仅停留于align-items在单行时生效,align-content在多行时生效,然后就问自己单行时是指什么时候?多行时又是指什么时候?

此时的我完全一脸懵*,看来是之前在学习这些知识的时候没有好好深入去了解它额?,既然发现了,就好好的去补上它吧,阅读完这个Stack Overflow上的回答以及W3C,再加上自身的一些理解,来整理一下flex-wrap和align-self,align-items以及align-content之间的关系

图解

image.png

  • 看完上图你可能会产生如下疑问
    • 1 . 为何要给行加上【】?
    • 2 . 何为单【行】弹性容器以及多【行】弹性容器 ?
    • 3 . 【行】与弹性线是什么意思 ?
    • 4 . align-content为何画在【行】的下面,align-items和align-self为何画在弹性线的下面?

对此我将会在下面一一分析,最后引用Stack Overflow的七个Example来进行一波分析,来彻底弄清楚flex-wrap和align-items,align-self,align-content之间的关系

缘由

  • 一个页面是由许多个Box组成的,而每个Box的类型由display来指定,而不同类型的盒子又被归为:Inline-level Box,Block-level Box,run-in Box,其中run in Box中含有flex container,它会创建相应的FFC,然后内部的盒子根据其规则进行布局

  • 通过指定display为flex或inline-flex从而使Box变为flex container,组成如下图

    image.png

    • 弹性容器的主轴方向是由flex-direction来决定的,而它的类型是由flex-wrap来决定的,因此针对疑问1是因为主轴方向是可以改变为水平(行)或垂直方向(列)

    • 针对疑问2,给出创建不同弹性容器时,弹性容器内形成的【行】的图

      • 单行弹性容器

      image.png

      • 多行弹性容器

      image.png

      而我所画的图中的【行】即上图中两条红线间的区域

    • 针对疑问3,弹性线(flex-line)就是存在于每一个【行】中,由弹性线来引导着弹性容器内每个flex-item进行排列

      • 如上图的单行弹性容器中,因为align-item的默认值为flex-start,所以它的弹性线就在【行】的顶部

        如果设置align-item为flex-end,那么弹性线就来到了【行】的底部,因此flex-item就会从下往上进行排列,设置为center同理

    • 而对于疑问4,如下解释

      • align-items作用的对象是【行】的弹性线,align-self作用的则是自身的弹性线

        【行】的弹性线由每个flex-item的弹性线组成
        align-self覆盖align-items对该元素起的作用

      • align-content作用的对象是【行】

        如:stretch将交叉轴剩余空间分配给每个【行】,而flex-start则是将每个【行】沿着交叉轴正方向进行排列,等等都可以解释

总结七个Example

源代码

<flex-container>
    <flex-item></flex-item>
    <flex-item></flex-item>
    <flex-item></flex-item>
    <flex-item></flex-item>
    <flex-item></flex-item>
    <flex-item></flex-item>
</flex-container>
复制代码
flex-container {
    display: flex;
    width: 250px;
    height: 250px;
    background: silver;
}
flex-item {
    flex: 0 0 50px;
    height: 50px;
    margin: 5px;
    background-color: lightgreen;
}
复制代码

Example1和2

在上述的css中添加

flex-container {
    flex-wrap: nowrap => wrap || wrap-reverse;
    align-content: flex-start;
}
flex-item:last-child {
    align-self: flex-end;
    background: crimson;
}
复制代码
  • 其实无论是单【行】弹性盒子或多【行】弹性盒子,align-self都会起作用,因为存在【行】,那么就会有一条弹性线,而align-self作用的对象就是元素自身的弹性线,下图就是将自身的弹性线移到了【行】底部

    image.png

  • 而此处,由单【行】弹性盒子变为多【行】弹性盒子,首先align-content通过移动【行】,使得其沿交叉轴正方向排列,而对于align-self其实它并没有失效,因为它将自身的弹性线移动到【行】的底部后,该元素的布局效果和不移动时是一样的!

    image.png

Example3和4

在上述的css中添加

flex-container {
    flex-wrap: nowrap => wrap || wrap-reverse;
    align-items: flex-end;
    align-content: flex-start;
}
复制代码
  • 在单【行】弹性容器中align-items通过移动【行】的弹性线到【行】底部,使得每个flex-item验证交叉轴的负方向排列

    因为此处每个flex-item都没有改变它的align-self的值,即默认为auto,所以不会它们不会移动本身的弹性线

    image.png

  • 而在多【行】弹性容器中align-content通过移动【行】,使得每个flex-item沿着交叉轴正方向排列,而此处的align-items虽然也将每个【行】的弹性线移动到【行】底部,但效果和不移动一样

    image.png

Example5和6和7

flex-container {
    flex-wrap: wrap | wrap-reverse;
}
flex-item:nth-child(2) {
    align-self: flex-end;
    background: red;
}
复制代码
  • 在多【行】弹性容器中由于align-content的默认值stretch将每个【行】平分交叉轴上剩余的空间,从而使得【行】变大了,同时移动第二个flex-item的弹性线到该【行】的底部,从而改变它的布局(即以弹性线为起点,沿交叉轴负方向排列)

    image.png

扩展聊聊flex-grow、flex-shrink和flex-basis

  • 首先flex-grow、flex-shrink都是在主轴方向上生效的

    • flex-grow按比例将该【行】的剩余空间分配给【行】的每个flex-item
    • flex-shrink则是要求【行】的每个flex-item按公式缩小大小以不超出弹性容器
      • boxj需要缩减的长度(i从1到【行】的flex-item元素数量,j是其中一个)

        (boxj-contentLength of main axis) * (boxj-flex-shrink)
        —————————————————————————— * 在主轴上超出的长度
        Σ[(boxi-contentLength of main axis) * (boxi-flex-shrink)]

    • box1需要缩减的长度 = [120 * 1 / (120 * 1 + 120 * 1 + 320 * 3)] * 200 = 20

      200 – 20 = 180

    • box2需要缩减的长度 = [120 * 1 / (120 * 1 + 120 * 1 + 320 * 3)] * 200 = 20

      200 – 20 = 180

    • box3需要缩减的长度 = [320 * 3 / (120 * 1 + 120 * 1 + 320 * 3)] * 200 = 160

      400 – 160 = 240

    flex-container {
      display: flex;
      flex-flow: row wrap;
    
      width: 600px;
      height: 600px;
      border: 2px solid red;
    }
    
    flex-item {
      width: 200px;
      height: 200px;
      box-sizing: border-box;
    
      padding: 0 40px;
      background: #f0f;
    }
    
    flex-item:nth-of-type(2) {
      background-color: #ff0;
    }
    flex-item:nth-of-type(3) {
      width: 400px;
      flex-shrink: 3;
      background-color: #0ff;
    }
    复制代码
    <flex-container>
        <flex-item></flex-item>
        <flex-item></flex-item>
        <flex-item></flex-item>
    </flex-container>
    复制代码
  • 再聊聊flex-basis与max-width/height、min-width/height、width/height之间的关系

    推荐此文章:The Difference Between Width and Flex Basis

    并且推荐一下该作者的Flexbox Zombies教育游戏(免费的,挺有意思的)

注意点

  • 为什么没有’justify-items’和’justify-self’属性?

    • 如我需要将单行弹性容器的最后一个flex-item放置在右下角,如果有justify-self情况下,那么可以通过justify-self: flex-endalign-self: flex-end完成,但实际上justify-self的设置并不能生效,我个人偏向于没必要,因为可以通过margin: auto平分剩余的水平和垂直空间来实现效果,就可以使用margin-left: autoalign-self: flex-end
  • 被不换行的内容撑开的Box,flex-shrink对它无效

可以被不换行文字或子元素撑开父元素(flex-item),这样它本身的flex-shrink就不会生效

flex-container {
    display: flex;
    width: 600px;
    height: 600px;
    border: 5px solid red;
}
.sonBox {
    background: chocolate;
    width: 400px;
    height: 100px;
}
flex-item:nth-child(2) {
    background: blueviolet;
    width: 200px;
    height: 200px;
}
flex-item:nth-child(3) {
    background: cornflowerblue;
    width: 200px;
    height: 200px;
}
复制代码
<flex-container>
    <flex-item>
      <div class="sonBox"></div>
    </flex-item>
    <flex-item></flex-item>
    <flex-item></flex-item>
</flex-container>
复制代码

圣杯布局

  • 最后运用所学知识,写一个圣杯布局,不是简简单单

  • header、footer固定占的高度20%,中间高度自适应

  • left、right固定宽占20%,center宽自适应
    image.png

<flex-container>
    <header></header>
    <div class="content">
      <div class="left"></div>
      <div class="center"></div>
      <div class="right"></div>
    </div>
    <footer></footer>
</flex-container>
复制代码
flex-container {
    display: flex;
    flex-flow: column nowrap;
    height: 500px;
    width: 500px;

    overflow: hidden;
    resize: both;
}

header,footer {
    flex-basis: 20%;
    background: crimson;
}

div.content {
    display: flex;
    flex: 1 1 auto;
}
.left,.right {
    flex-basis: 20%;
    background: chocolate;
}
.center {
  flex: 1 1 auto;
  background: goldenrod;
}

复制代码

总结

  • 此文章是提炼出来 + 自身理解的笔记,还是推荐感兴趣的读者去阅读Stack Overflow以及w3c
  • 文章有不对的地方,欢迎大家讨论,我会有则改之,无则加勉的
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享