不少谈 Flex 布局的文章都是一个一个属性的干聊,有点像约会时的查户口,枯燥而无趣。css
若是让你硬记中国 34 个省级行政单位,你不只会记的很吃力,可能还无法分清省和省之间的相邻关系。而一旦你心中有了一副中国地图,这些知识就变成信手拈来的东西了。html
这篇文章立志作 Flex 布局的中国地图。git
本文是『horseshoe·Flex专题』系列文章之一,后续会有更多专题推出github
GitHub地址(持续更新):horseshoe布局
博客地址(文章排版真的很漂亮):matiji.cnflex
若是以为对你有帮助,欢迎来 GitHub 点 Star 或者来个人博客亲口告诉我ui
Flexbox叫弹性盒模型,它的使用场景主要是屏幕自适应布局和取代浮动布局。flexbox
细节性的知识须要大量实践,系统性的知识则须要真正理解系统。我认为Flexbox就属于系统性的知识。因此这篇文章从概念入手,力求作到只要阅读一遍,就可让开发者心中有乾坤。spa
你他妈多是三体
看多了吧,啥叫一维布局模型?翻译
一维布局模型,简单讲就是,在主轴
方向肯定的状况下,只有行
,没有列
。
咱们熟悉的二维布局模型有哪些呢?有display: table
和display: grid
。而咱们今天要讲的display: flex
就是妥妥的一维布局模型了。
直接看图。
能够看到,Flexbox有行
的概念,却没有列
的概念。这致使它的表达能力是受限的。
咱们如何肯定一条短线是中文的一
仍是阿拉伯数字的1
呢?
你可能以为我在搞笑。一眼看过去,横向的不就是中文的一
,纵向的不就是阿拉伯数字的1
么。
是的。那是由于咱们遵循着一些默认的约定:两眼连成的线肯定了水平方向。
Flexbox也是这个道理。它是一个一维布局模型,咱们就要找到肯定仅有的维度的那根线。
这就引出了Flexbox的第一个概念:主轴(mian axis)与交叉轴(cross axis)。主轴就是那根仅有的维度线。两眼连成的线与主轴方向保持平行,这就是肉眼看待Flexbox的正确方式。不然有时候它会显得很别扭。
而后咱们再来讲弹性盒子。既然它是一个盒子,那确定得有容器,也得有内容。
也就引出了Flexbox的第二个概念:弹性容器(flex container)与弹性项目(flex item)。
你能够将弹性容器理解为冷战时期的柏林,各方国际政治势力天然就是若干弹性项目了。几个国际大流氓聚在一块儿开会讨论什么呢?固然是开会讨论如何瓜分柏林咯。是的,弹性盒模型讨论的就是弹性项目如何瓜分弹性容器这一舒适的话题。
上一小节咱们提到过,Flexbox是一维布局模型。它带来的结果就是Flexbox有行
的概念,却没有列
的概念。
因此引出Flexbox的第三个概念:行(line)。
直接看图。
若是弹性容器有富余空间,那好说,你们分就是了。而若是弹性容器空间不够,弹性项目不只没得分,你们还得挤一挤。那么问题就来了,挤不是无限制的挤,我们就来探讨一下,挤到什么程度,是可忍孰不可忍?
举个例子。
.container {
display: flex;
width: 850px;
padding: 5px;
}
.container .item {
width: 200px;
height: 50px;
margin: 5px;
}
.container .item:nth-child(2) {
width: 1000px;
}
复制代码
两个弹性项目的长度加起来的和已经超过了弹性容器,因此不得不挤压。挤压的比率我们先不考虑,我们先观察挤压的方式。有没有发现红色部分都有不一样程度的收缩,可是黄色部分却岿然不动?
黄色部分是什么?是弹性容器的padding
和弹性项目的margin
。盒子模型我们都了解吧,除了padding
、margin
和border
以外,是否是只剩content
了?
我们能够大胆猜想,Flexbox只敢欺负盒子模型的content
,其他都是大爷,惹不起。
别急,再来验证一下。
.container {
display: flex;
width: 850px;
padding: 5px;
}
.container .item {
width: 200px;
height: 50px;
margin: 5px;
}
.container .item:nth-child(2) {
width: 1000px;
padding: 0 450px;
}
复制代码
这下是否是很清楚了?第一个弹性项目的content
长度已经变成了0;第二个也好不到哪去,由于盒子长度都被padding
占据,它的content
长度实际上也是0。都把人家挤破产了,却丝绝不敢动其余的属性,势利眼无疑了。
咱们再来看一个有意思的例子。
.container {
display: flex;
width: 850px;
padding: 5px;
}
.container .item {
width: 200px;
height: 50px;
margin: 5px;
}
.container .item:nth-child(2) {
width: 1000px;
padding: 0 300px;
}
.container .item .inner {
width: 500px;
height: 100%;
}
复制代码
我在第二个弹性项目中放了一个长500px
的元素,结果你猜怎么着,弹性项目的padding
居然有一部分和元素重合了。连子元素都未能幸免。
通常来讲盒子模型的content
都是被文字撑开的,咱们最后再来看看文字的状况。
在弹性项目显式设置了宽度的状况下,弹性项目并不能彻底包裹文字。也就是说文字也帮不了它,既然它声明了宽度,文字撑开的长度最多不能超过显式声明的宽度,超出的文字只能溢出。
而没有显式声明宽度的状况,文字的宽度就是弹性项目盒子模型的content
,Flexbox也拿它没办法。
总结一下:当富余空间不够时,Flexbox只会挤压弹性项目的
content
,其他如padding
、margin
和border
彻底不受影响。同时弹性项目没有显式声明宽度的状况下,Flexbox也不会挤压文字。
从这里开始,咱们就要讲具体的CSS属性了。
display
有两个和Flexbox相关的属性,分别是display: flex
和display: inline-flex
。
对于容器内部的项目来讲,效果是同样的。它们的区别在于容器自身应该以块元素仍是行内元素的身份立命。包括table
也有这样的区分,就很少讲了。
这个属性声明的是主轴的方位和方向。
首先,主轴可不必定是水平的,主轴切换了那可就什么都变了。
其次,主轴声明的信息有两个,分别是:
因此这里也涉及到四个属性值。
.container {
flex-direction: row(default) | row-reverse | column | column-reverse;
}
复制代码
这个属性声明的是当容器中的项目一行放不下的时候,是让你们挤一挤呢,仍是换行。
其实这里也包含两个信息:
.container {
flex-wrap: nowrap(default) | wrap | wrap-reverse;
}
复制代码
若是把flex-direction
和flex-wrap
结合起来,你们会不会懵逼?上上下下左左右右。其实无论它怎么reverse,flex-direction
反转的是主轴的方向,flex-wrap
反转的交叉轴的方向。
抓住一些概念性的东西,就不会懵逼了。
这是一个集合属性,能够同时定义flex-direction
和flex-wrap
。
也就是说,这一个属性能够一站式声明主轴和交叉轴的特性。
.container {
flex-flow: row-reverse wrap-reverse;
}
复制代码
这个属性声明每行内的项目如何水平对齐。
把弹性容器一行内的项目想象成一行行内元素,justify-content
和text-align
的食用方式是同样的。
.container {
justify-content: flex-start(default) | flex-end | center | space-between | space-around | space-evenly;
}
复制代码
flex-start
、flex-end
和center
很是表意,我们按下不表。
解释一下后面三个属性值:
space-between
表示两头的项目对齐容器壁,项目与项目之间的空隙平均分配。所谓的between
指的就是项目之间。space-around
表示两头的项目与容器壁保留一个单位的空隙,项目与项目之间保持两个单位的空隙。around
翻译成中文是周围
,指的就是每一个项目左右两边的空隙平均分配。space-evenly
表示两头的项目与容器壁之间的空隙和项目与项目之间的空隙都保持一个单位。evenly
翻译成中文是均匀
,指的是全部空隙平均分配。这个属性声明每行内的项目如何垂直对齐。
.container {
align-items: stretch(default) | flex-start | flex-end | center | baseline;
}
复制代码
这里有一个问题,若是弹性项目显式的声明了高度,那stretch
将再也不起做用。因此这里的例子,我往项目中加了一个子元素,把高度显式的声明在子元素上,这样项目的高度就是被撑开的。
<div class="container">
<div class="item"><div class="inner">1</div></div>
<div class="item"><div class="inner">2</div></div>
<div class="item"><div class="inner">3</div></div>
</div>
复制代码
能够看到,默认状况下,行内的弹性项目会拉伸,至关于声明了高度100%
。一旦项目显式的声明了高度,拉伸就再也不起做用了。
这个属性将容器的一行视为最小单位。它声明的是若是容器的交叉轴方向有富余空间,每行应该如何垂直对齐。
.container {
align-content: stretch(default) | flex-start | flex-end | center | space-between | space-around | space-evenly;
}
复制代码
这里也同样,若是弹性项目显式的声明了高度,那stretch
将再也不起做用。
同时有两点须要注意:
align-content
属性将没法生效,由于它是做用于行的,只有一行也敢叫老子跑一趟?justify-items
若是你同时了解display: flex
和display: grid
,也许你会发现它们都有xx-items
和xx-content
属性。可是别急,再进一步深究,发现Flexbox少了一个justify-items
。
咱们先来阐述一下xx-items
和xx-content
做用范围有什么区别。
xx-items
做用于项目,这意思很明朗。xx-content
又是做用于什么呢?确定是比项目更大的单位,又联想Flexbox的align-content
是做用于行,咱们能够大胆猜想xx-content
做用于行或者列。点破到这里,你们应该有点眉目了吧?Flexbox是一维布局模型,它根本没有列的概念。
你说不对呀,既然Flexbox没有列的概念,那不是应该没有justify-content
属性,而应该有justify-items
属性么?
话是这么说,我当初也是这么认为的。
但后来仔细想想,Flexbox的align-items
声明的是一行内的项目如何垂直对齐,与之相对,justify-items
声明的就应该是一列内的项目如何水平对齐。好像更离谱。而若是将弹性容器一行内的每一个项目都当作一列,justify-content
彷佛就说的通了。
这就比如讨论螃蟹的螯究竟是不是手同样,怎么都以为别扭。只能找一个相对更合理的说法了。
提出这个问题没别的意思,只是想加深你们对Flexbox的理解。
从这里开始,涉及到的属性都是弹性项目自身的属性。在大的格局肯定的状况下,项目之间也是能够有一些腾挪空间的。
这个属性声明的是弹性项目自身的次序。只要显式声明了不是默认值0的整数,项目显示的次序将会不一样于源代码定义的次序。
这个主要是留给JavaScript动态控制项目的次序用的,非动态直接修改源代码的次序就行了。
.item {
order: <integer>; /* default is 0 */
}
复制代码
这个属性声明的是弹性项目是否要瓜分行内的富余空间,以及如何瓜分。
属性值只容许正整数。
.item {
flex-grow: <number>; /* default is 0 */
}
复制代码
首先解释一下什么是富余空间:它是在弹性容器规则和弹性项目显式宽度或者内容的共同约束下,行内剩余的水平空间。好比图例中除去margin
、padding
的黄色部分。
行内的富余空间是如何被瓜分的呢?
首先,弹性项目要提出申请。好比第一个项目提出flex-grow: 1
,意思是说它想要一份富余空间。至于一份富余空间是多少像素,目前还不能肯定。
等全部项目都申请完毕,计算申请的总份数。已知富余空间长度和申请总份数,就能知道一份富余空间是多少像素。
最后根据每人提出申请的份数,分配富余空间。
只有当行内有富余空间时,
flex-grow
属性才会生效。行内空间已经预先被瓜分完甚至不够时,该属性就管不了了。
这个属性声明的是弹性项目是否要瓜分行内的负债空间,以及如何瓜分。
属性值只容许正整数。
.item {
flex-shrink: <number>; /* default is 1 */
}
复制代码
一样,解释一下什么是负债空间:它是在弹性容器规则和弹性项目显式宽度或者内容的共同约束下,行内短缺的水平空间。此时若是不换行的话,就要求挤压弹性项目的长度。
行内的负债空间的瓜分规则与富余空间的瓜分规则大体相同。
首先,弹性项目要提出申请。只不过这时的份额就再也不是我要多少,而是我还多少。
等全部项目都申请完毕,计算申请的总份数。
这里的问题在于,计算负债空间的长度稍微比较复杂。咱们在文章一开始探讨过弹性项目最小长度的话题,这里再次总结一下:
content
,其他如padding
、margin
和border
不受影响。最后根据每人提出申请的份数,分配负债空间。就是还债。
为何
flex-grow
属性的默认值是0,而flex-shrink
属性的默认值是1呢?由于默认状况下,若是有富余空间我能够不要的,可是有负债空间又没法换行的话,我不得不要。因此
flex-shrink
属性的默认值是1,意思就是默认状况下,若是空间不够则你们平均的被挤压。你能够将全部项目的
flex-shrink
属性值设置为0,如此这般全部项目都铁骨铮铮、不畏强权了。见上面图例的第四个例子。
这个属性声明的是预先分配给弹性项目的长度。它是width
属性的替代品,优先级比width
高。
.item {
flex-basis: <length> | auto; /* default is auto */
}
复制代码
若是width
和flex-basis
都显式的声明了一个非auto
的值,那么flex-basis
的优先级更高。不然,哪一个显式声明了就以哪一个为准。
确实不太清楚制定flex-basis
属性标准的意义何在。
它们的区别好像仅限于属性值为0的状况。width: 0
咱们都知道表示没有宽度,见上面图例的第二个例子;而flex-basis: 0
表示之内容的宽度为宽度,见上面图例中的第三个例子。
这是一个集合属性,能够同时定义flex-grow
、flex-shrink
和flex-basis
。
你能够集合三个属性的值,也能够只写flex-grow
一个属性的值。
.item {
flex: <'flex-grow'> | <'flex-grow'> <'flex-shrink'> <'flex-basis'>;
}
复制代码
这个属性声明的是弹性项目自身在行内的垂直对齐方式。
“我就是我,是颜色不同的烟火”。
.item {
align-self: auto(default) | stretch | flex-start | flex-end | center | baseline;
}
复制代码
除了auto
以外,align-self
的属性值和align-items
的属性值是同样的,效果也同样。
align-items: auto
是说我默认服从集体,不自搞一套,因此才会多这么个属性值。
为何有
align-self
属性而没有justify-self
属性呢?这个问题咱们讨论过吧?由于没有
jusifty-items
属性,因此justify-self
属性也无从谈起。你看人家Grid就有
justify-self
属性。
有一个小游戏 Flexbox Froggy 能够帮助你轻松的实践Flexbox的各项特性。
本文是『horseshoe·Flex专题』系列文章之一,后续会有更多专题推出
GitHub地址(持续更新):horseshoe
博客地址(文章排版真的很漂亮):matiji.cn
若是以为对你有帮助,欢迎来 GitHub 点 Star 或者来个人博客亲口告诉我