理解flex-basis和align-content

阅读w3c规范中flex部分,并对flex尺寸计算和对齐计算过程进行重点记录,其中重点解释flex-basisalign-content,也会涉及flexauto marginflex lines等概念。

首先要需要了解:flex布局先计算尺寸,再进行布局。

计算尺寸

除了设置尺寸属性外,flex-basis也决定元素在flex容器中占据的尺寸。

flex-basis

// flex-basis
the initial main size of the flex item, before free space is distributed according to the flex factors.

在自由空间根据弹性系数进行分配之前,flex item的初始主尺寸(又有基准尺寸这一说法)。

flex-basis有三种取值:

  • auto
  • content
  • width:计算方式和盒模型中的widthheight计算方式相同

其默认值是:0。

图片

flex-basis设置为0,则初始主尺寸为0,那么按1 1 2分配的话,三个flex item的总尺寸比是1:1:2

flex-basis为auto时表现却不一样。

看看flex-basis:auto的解释:

When specified on a flex item, the auto keyword retrieves the value of the main size property as the used flex-basis. If that value is itself auto, then the used value is content.

auto值使得尺寸计算会检索并使用flex item的main size propertywidthheight)作为其flex-basis的值,如果flex元素本身的尺寸是auto(如不显式指定尺寸),则取值为元素内容的尺寸。

在空间分配初始,根据总空间 - flex-basis空间 = 剩余可分配空间计算剩余空间。再根据flex-growflex-shrink对剩余空间进行分配。

故第一种情况下,内容空间均为0,剩余空间分配后,三者占比为1:1:2。第二种情况,内容空间为内容的尺寸,所以剩余空间分配后是1:1:2,三个flex item所占的主轴空间并不等于是1:1:2

如果同时显式指定flex-basis和width,会发生什么呢?

// html
<div class="wrp">
    <div class="item item1">short</div>
    <div class="item item2">loooooooooog</div>
    <div class="item item3">short</div>
</div>

// css
.wrp {
    border: 1px solid black;
    display: flex;
    flex-wrap: nowrap;
    width: 400px;
}
.wrp .item {
    border: 1px solid grey;
    box-sizing: border-box;
    /* flex-basis: 0; */
    flex-basis: auto;
}
.wrp .item1 {
    width: 100px;   
}

flex-basis: 0时:

图片

flex-basis: auto时:

图片

flex-basis: auto时,通过css设置的宽度才会被考虑,此时.item1的宽度才明显宽于.item3

flex

flex属性是对<flex-grow> <flex-shrink> <flex-basis>的简写,其取值包括

  • initial: 0 1 auto.
  • auto: 1 1 auto
  • none: 0 0 auto
  • positive-number: positive-number 1 0

最后一种常取值为1,例如将某一个flex item设置flex: 1,其他弹性元素不进行设置,那么这个元素将占用所有的剩余空间。

Alignment

当flex容器结束flex item layout且所有子元素的尺寸都确定后,它们将在容器内部进行对齐。

除了flex及flex item的对齐属性外,其他属性也会影响元素的展现位置,例如marign、绝对定位、浮动等。绝对定位、浮动都会使元素脱离flex布局流,也就是成为了非flex item,所以对齐时计算分配空间时,也不会考虑这部分元素。margin属性的效果则不同。

align by auto margin

规范特别提到为一个flex item设置margin: auto属性。

设置margin: auto,则:

  • 在计算flex base和flexible length时,auto margin被视为0。
  • 在通过justify-content和align-self进行对齐之前,任何正向可用空间都将分配给该维度中的auto margin。
  • 忽略溢出的盒子的自动边距 并向结束方向溢出。

利用上述特型,我们很容易就能实现典型的导航结构:


图片

代码:

// html
<nav>
  <ul>
    <li><a href=/about>About</a>
    <li><a href=/projects>Projects</a>
    <li><a href=/interact>Interact</a>
    <li id="login"><a href=/login>Login</a>
  </ul>
</nav>
// css
nav > ul {
  display: flex;
  border: 1px solid black;
}
nav > ul > li {
    width: 100px;
}
nav > ul > #login {
  margin-left: auto;
}

当设置最后一个元素margin: auto后,所有的剩余空间先分配给它。因此flex对齐属性justify-content对该元素无效。

如果margin设置为数值,从样式表现来看,margin值会影响剩余空间的分配,此时margin会被纳入content尺寸的计算。具体计算公式和计算时机目前还没有找到。。

需要注意的是!弹性布局容器中的margin是不折叠的。

justify-content、align-items和align-self

它们在所有弹性长度和自动边距都确定后才进行对齐计算,也能控制溢出 flex lines的元素。flex lines在下文会讲到。

它们的优先级低于margin,设置auto margin后,它们就失效了。

// html
<nav>
  <ul>
    <li><a href=/about>About</a>
    <li><a href=/projects>Projects</a>
    <li><a href=/interact>Interact</a>
    <li id="login"><a href=/login>Login</a>
  </ul>
</nav>
// css
nav > ul {
  display: flex;
  border: 1px solid black;
  height: 100px;
  justify-content: center;
  align-items: flex-start;
  width: 500px;
}
nav > ul > li {
    width: 100px;
}
nav > ul > #login {
  margin-left: auto;
  margin-top: auto;
}
图片

align-content

说到align-content,必须和align-items做个对比。

// align-content:
The align-content property aligns a flex container’s lines within the flex container when there is extra space in the cross-axis, similar to how justify-content aligns individual items within the main-axis. Note, this property has no effect on a single-line flex container.

// align-items:
align-items sets the default alignment for all of the flex container’s items, including anonymous flex items.

align-itemsjustify-content类似,不同在于前者设置容器中的items在交叉轴上的对齐方式。

align-content适用于multi-line的flex容器,当交叉轴有多余空间时,它设置容器内flex lines的对齐方式,和justify-content在主轴上对齐单个元素类似。

要理解定义,还需要了解Flex linesmulti-line

flex lines和multi-line

flex lines可谓是flex布局的重点。

弹性布局容器中的元素沿着flex lines对齐,若干虚拟container被布局算法用来分组和对齐(平行于主轴方向)。一个弹性布局容器要么是单行要么是多行,取决于flex-wrap属性。

  • 一个单行容器(如:flex-wrap: nowrap)将所有子节点放在同一行中,即使这可能导致其内容溢出。

  • 一个多行容器(如:flex-wrap:wrapflex-wrap:wrap-reverse)将其flex item分为多行,类似于文本因为太宽无法适应当前行而被分到新的一行展示一样。当额外的line被创建后,根据flex-wrap属性,容器将它们沿着容器内的交叉轴堆放。每一行都包含至少一个flex item,除非弹性容器本身是完全empty的。

一旦内容被分为多行,每行的布局就是独立的。弹性长度和justify-content以及align-self属性一次只考虑单一一条flex line上的items。

在多行flex容器中(即使只有一行),每一行的交叉轴尺寸都是包含行上的弹性项目所需的最小尺寸(在align-self对齐之后),并且交叉轴上的lines使用align-content属性在flex容器中对齐。

在单行flex容器中,line的交叉轴尺寸是flex容器的交叉轴尺寸,align-content不起作用。line的主轴尺寸总是和flex容器的内容盒子的尺寸相同。

举个例子:

<div class="wrp wrp1">
    <div>first line</div>
    <div>second line</div>
</div>
<div class="wrp wrp2">
    <div>first line</div>
    <div>second line</div>
</div>
<div class="wrp wrp3">
    <div>first line</div>
    <div>second line</div>
</div>
// css
.wrp {
    border: 1px solid black;
    display: flex;
    flex-wrap: wrap;
    height: 80px;
    width: 100px;
    margin-bottom: 10px;
}
.wrp > div {
    width: 100%;
    height: 20px;
    border: 1px solid grey;
}
.wrp1 {
    align-items: center;
}
.wrp2 {
    align-content: center;
}
.wrp2 div:first-child {
    align-self: flex-start;
}
.wrp3 {
    flex-wrap: nowrap;
    align-items: flex-start;
}
.wrp3 div:first-child {
    align-self: flex-end;
}
图片

.wrp2中,根据multi-line弹性布局容器中每条交叉轴上的flex line的尺寸是包含弹性项目所需的最小尺寸原则,那么容器中的两个交叉轴上的line将都是20,所以设置align-content: center后,二者始终并排居中。

虽然.wrp1也是一个多行弹性布局容器,但.wrp1没有显式指定align-content(其默认值为stretch),而指定了align-items:center。看stretch的定义:

Lines stretch to take up the remaining space. If the leftover free-space is negative, this value is identical to flex-start. Otherwise, the free-space is split equally between all of the lines, increasing their cross size.

align-content: stretch使得flex lines拉伸以占据剩余空间。如果剩余空闲空间为负值,则此值与flex-start相同。否则,自由空间会在所有行之间平均分配,从而增加它们的在交叉轴的尺寸。

所以.wrp1中每条flex line在交叉轴上的尺寸都是: flex容器的尺寸 / 2 = 40。根据align-itemsjustify-content相似的定义,可以推测这个属性一次也只考虑以单一一条flex line上的items。所以.wrp1中的每行flex line中的flex item都在其line上垂直居中。

.wrp3属于单行容器,所以其flex line占据中交叉轴的全部尺寸。

最后,对Alignment内容总结,有如下要点:

  • flex布局容器中,由flex line决定元素对齐位置的范围。
  • 多行flex lines情况下,每行都有独立的布局范围,互不影响,其交叉轴尺寸默认是包含弹性项目所需的最小尺寸
  • 单行flex line容器的flex line尺寸和交叉轴尺寸相同。

总结

  • flex布局通过display: flex指定。其子元素会形成类似inline-block块。
  • flex容器内部没有margin折叠,auto margin计算优先于flex的对齐属性。
  • 理解flex lines的概念很重要。flex-wrap: nowrap的容器是single-line,而flex-wrap: wrap则导致出现multi lines container,每个flex-item的尺寸计算基于其所在的line。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 移动开发基本知识点 一.使用rem作为单位 html { font-size: 100px; } @media(m...
    横冲直撞666阅读 3,521评论 0 6
  • H5移动端知识点总结 阅读目录 移动开发基本知识点 calc基本用法 box-sizing的理解及使用 理解dis...
    Mx勇阅读 4,635评论 0 26
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,815评论 1 92
  • 雨后的日子阅读 227评论 3 2
  • 郭芳艳 焦点网络五期 坚持原创分享第58天 昨天虽然只听了半节课,但是却听到了一个很有意义和价值的观点,...
    冰山蓝鹰阅读 135评论 0 0