理解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。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容

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