俗话说:光说不练,等于白干.又曰知行合一,日进千里.
前面已经将flex布局的所有概念都做了详细的总结,但是总感觉距离掌握这玩意儿, 还差点意思,我冥思苦想,总算明白了,还得是实践操作几波,才能用好 flex 布局这把尖刀.
想到哪干到哪,下面基于概念篇 做详细的实操,本篇默认都已 熟悉flex布局的各种概念,看不下去的观众老爷,请移步概念篇.
flex 布局的容器探索
概念篇 我们有说到 要成为 flex 布局的容器,只需要给一个html 元素 添加上 dispaly:flex,或者dispaly:inline-flex,就可以了.这两种方式决定了 容器 容器本身的排布方式.
<span>span1</span>
<div class="container">container</div>
<span>span2</span>
方式一: dispaly:flex
.container {
background-color: aqua;
display: flex;
}
方式二: dispaly:inline-flex
.container {
background-color: aqua;
display: inline-flex;
}
可以看到 dispaly 为flex 时,容器是块级元素,宽度默认占一行,与块级元素特征一致.
为inline-flex时,容器是行内块级元素,其宽度由其内部的元素的宽度的总和.
另外也可以看出来,被设置成容器的html元素,依然处于标准流中,并没有脱标.
容器的伸缩性
当不设置 容器的宽度和高度时,容器时一定能保障,在容器内的flex-item 是在容器内的,因为容器是包裹其内的flex-item的,此时容器的宽高会伸缩.
当设置 容器的宽度和高度时,容器的宽度和高度就是固定的,不会伸缩,不保证 能包含其内的所有flex-item. 如果要保障所有元素 都在容器内,请设置换行:flex-wrap:wrap
.container {
background-color: aqua;
/* width: 800px; */
/* height: 150px; */
width: 150px;
height: 100px;
/* max-width: 150px; */
display: flex;
/* overflow: scroll; */
/* flex-wrap: wrap; */
/* flex-direction: column; */
/* flex-direction: row; */
}
.item {
width: 50px;
height: 50px;
min-height: 50px;
min-width: 50px;
border: 1px solid orange;
border-radius: 5px;
background: greenyellow;
box-sizing: border-box;
}
<div class="container">
<span class="item">item1</span>
<div class="item">item2</div>
<i class="item">item3</i>
<i class="item">item3</i>
<i class="item">item3</i>
</div>
3.容器属性探索
需要明确说明的一点是,flex 布局是 一种一维布局方式.一维是线性的,横向或者竖向.
在一维中的区域中,通过flex 布局 我们可以为所欲为,任意布局,但在处理多行布局时,此时的布局已经是二维的了,flex 布局处理起来有很多地方是差强人意的,这不是你用的不好,也不是flex布局不行,而是flex 布局的出现,本身就不是针对这种场景的.
如果想更好的处理二维 布局的问题,可以使用更强大的布局方式 grid 布局,但是兼容性是一大考验. 比较好的方式是通过flex 布局与标准流,浮动,定位等布局方式相结合,达到更好的效果.
单行布局探索
flex-direction
- flex-direction 决定了flex 布局的主轴方向,可以是从左到右,从右向左,从上到下,从下到上.
- 同时,flex-dirction 也决定了 交叉轴的方向,
- 主轴方向为水平(row,row-reserve)时,交叉轴方向为从上到下,
- 主轴方向为竖向时(column, column-reserve),交叉轴方向为水平从左到右
justify-content
- justify-content 决定了 主轴方向上的 对齐方式.
align-items align-items 决定了单行 flex items 在交叉轴的上的 对齐方式.
1. 设置flex-direction 改变主轴方向,默认flex-direction 是row ,代表横向,排布,如果我们将其设置为column 就变成了竖向排布.
.container {
background-color: aqua;
width: 200px;
height: 80px;
display: flex;
/* flex-direction: row; */
}
.item {
width: 50px;
height: 50px;
/* min-height: 50px;
min-width: 50px; */
border: 1px solid orange;
border-radius: 5px;
background: greenyellow;
box-sizing: border-box;
}
<div class="container">
<span class="item">item1</span>
<div class="item">item2</div>
<i class="item">item3</i>
</div>
修改 flex-direction 为column,
flex-direction: column
可以看到,flex item 的高度进行了收缩,以适应容器的高度,这是因为 flex-items 中 flex-shrink 的属性设置值决定的,如果不想让 flex item 收缩,可以设置 flex-item的flex-basis 或者 flex-item 的min-height,两者都可以 改变flex item 的 高度,使其不收缩,因为 这两者的优先级都高于 width,height 属性. 但是这也可能会导致 flex -item 超出其容器的范围,请综合考虑使用.
一个flex item size的 几种设置属性的 优先级高低
- max-width\max-height\min-width\min-height
- flex-basis
- width\height
- 内容本身的 size
2.修改justify-content 属性,改变 主轴方向上的 对齐方式.
justify-content: space-around.
flex-firection: row.
3. 修改align-items,改变交叉轴方向上的对齐方式
algin-items:flex-end.
4. 修改主轴方向, 再看 主轴 和交叉轴的 对齐 方式,理解主轴与交叉轴的概念
flex-direction:column;
align-items:flex-end;
多行 布局探索
多行布局主要是实践 flex-wrap 和 align-content 这两个属性.
flex-wrap
flex-wrap 的作用很简单,就是将主轴上放不下的flex item 进行换行,不至于超出容器的宽度. 这里附上代码
.container {
background-color: aqua;
width: 200px;
height: 120px;
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: flex-start;
align-items: flex-start;
/* align-content: stretch; */
}
.item {
width: 60px;
height: 60px;
/* min-height: 50px;
min-width: 50px; */
border: 1px solid orange;
border-radius: 5px;
background: greenyellow;
box-sizing: border-box;
}
<div class="container">
<span class="item">item1</span>
<div class="item">item2</div>
<i class="item">item3</i>
<span class="item">item4</span>
</div>
当容器的高度 超出两行的高度,并且flex-item的数量 不足3 行 时,flex 布局的显示会显得很奇怪. 比如我调整容器宽度为 200px 时,
此时 我们发现 item4 并没有 紧挨着item1,这是什么原因呢, 这里就涉及到容器的另外一个属性,align-content,虽然我们没有设置这个属性,但是它是有默认值的,默认值是stretch,看过概念篇的,stretch 值 会将 对应轴上的所有空间 都拉满.
而align-content 是以行为单位的,那么其实现在 交叉轴上 只有 两行,也就是有两个元素,由于两个元素的高度是固定的,而且无法沾满整个交叉轴的空间(60*2 = 120 < 200),而stretch的概念又要占满整个空间,此时怎么办呢?
此时 flex 布局会将 交叉轴 剩余的高度60,平均分给每一个元素,以此来保证stretch的概念,元素占满整个轴的空间.
至于这样做对不对,仁者见仁,智者见智,毕竟flex 布局只是 一种一维 布局方式,何必要求那么多呢.
align-content align-conetnt 主要要理解以下两个点:
- algin-content 是以 主轴 的一行 作为单位 来 设置 对齐方式的.
- align-conetnt 是在 多行情况下的 设置 交叉轴上的对齐方式的.
理解了这两个点就能更好的理解这个属性.
align-conetnt: center
.container {
background-color: aqua;
width: 200px;
height: 200px;
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: flex-start;
align-content: center;
}
.item {
width: 60px;
height: 60px;
/* min-height: 50px;
min-width: 50px; */
border: 1px solid orange;
border-radius: 5px;
background: greenyellow;
box-sizing: border-box;
}
<div class="container">
<span class="item">item1</span>
<div class="item">item2</div>
<i class="item">item3</i>
<span class="item">item4</span>
<div class="item">item5</div>
<i class="item">item6</i>
<span class="item">item7</span>
<div class="item">item8</div>
<i class="item">item9</i>
</div>
algin-conetent:space-between
flex-items 探索
flex-item 的类型特点
在概念篇我们 有提到,flex-item 不再严格区分块级元素和行内级元素,默认情况下是包裹内容,所有的flex-item 都被视为 行内级块级元素,我们可以设置它的宽度和高度,哪怕它本身是inline 元素.而 所有元素也会在同一行显示,那么它是块级元素
.container {
background-color: aqua;
display: inline-flex;
}
<div class="container">
<span>item1</span>
<div>item2</div>
<i>item3</i>
</div>
flex-items 的属性探索
1. order
可以通过设置某个 flex item 的order 属性,来改变 item 在 布局中的位置,值越小就越靠前
为 item3 添加 order 属性,可以看到 它的位置发生了变化
.container {
background-color: aqua;
width: 200px;
height: 100px;
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: space-around;
}
.item {
width: 60px;
height: 60px;
/* min-height: 50px;
min-width: 50px; */
border: 1px solid orange;
border-radius: 5px;
background: greenyellow;
box-sizing: border-box;
}
.item-order {
order: -1;
}
<div class="container">
<span class="item">item1</span>
<div class="item">item2</div>
<i class="item item-order">item3</i>
</div>
2.align-self
给 某个 flex item 设置 align-self,可以在这个flex item 上覆盖容器上设置的 align items,
简单说设置 align 可以单独设置 这个 flex item 在 交叉轴上的 对齐 方式.
.container {
background-color: aqua;
width: 200px;
height: 100px;
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: flex-start;
}
.item {
width: 60px;
height: 60px;
border: 1px solid orange;
border-radius: 5px;
background: greenyellow;
box-sizing: border-box;
}
.item-order {
order: -1;
}
.item-self {
align-self: center;
}
<div class="container">
<span class="item">item1</span>
<div class="item item-self">item2</div>
<i class="item">item3</i>
</div>
3.flex-grow
flex-grow 决定了 flex items 如何拓展 (拉伸/成长)
可以设置任意 非负数字( 正小数,正整数,0),默认值是 0
flex-grow 的使用 有一个 前提条件,就是 容器在 主轴方向有 剩余 size是, flex-grow 才有效.
如果 flex-items 的flex-grow 总和 sum 超过1,
- 每个felx item 拓展的size = 容器的剩余 size * flex-grow / sum
flex itmes 拓展后的最终 size 不能 超过 max-width\max-height
先来看看 主轴上 有剩余size 时的使用
.container {
background-color: aqua;
width: 200px;
height: 100px;
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: flex-start;
}
.item {
width: 60px;
height: 60px;
border: 1px solid orange;
border-radius: 5px;
background: greenyellow;
box-sizing: border-box;
}
.flex-grow {
flex-grow: 1;
}
<div class="container">
<span class="item">item1</span>
<div class="item flex-grow">item2</div>
<i class="item">item3</i>
</div>
可以 看到 item2 在主轴方向(水平方向)进行了拉伸.
但如果我们给 item2 设置上max-width 与width 相等,它就不会再生长.
.flex-grow {
flex-grow: 1;
max-width: 60px;
}
如果 把 item1 和 item2 都加上 flex-grow:1, 那么 item1,item2 会平分剩余空间
.flex-grow {
flex-grow: 1;
}
<div class="container">
<span class="item flex-grow">item1</span>
<div class="item flex-grow">item2</div>
<i class="item">item3</i>
</div>
4.flex-shrink
flex-shrink 决定了 flex itmems。如何收缩(缩小)
- 可以设置任意非负数字(正小数,正整数,0),默认值 是 1
- 当flex items 在 主轴 方向 上超过了 容器的size ,flex-shrink 属性才会有效 如果 所有 flex itms 的 flex-shrink 总和 超过 1,
- 每个felx item 收缩的size = flex items 超出容器的 size * 收缩比例 / 所有的 felx itmes的收缩比例 之和.
flex items 收缩后的最终size 不能小于 min-width\min-height
.container {
background-color: aqua;
width: 200px;
height: 100px;
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: flex-start;
}
.item {
width: 100px;
height: 100px;
border: 1px solid orange;
border-radius: 5px;
background: greenyellow;
box-sizing: border-box;
}
.flex-shrink {
flex-shrink: 3;
}
<div class="container">
<span class="item flex-shrink">item1</span>
<div class="item flex-shrink">item2</div>
<i class="item">item3</i>
</div>
5.flex-basis
**flex-basis 用来设置 flex itmes 在 主轴方向上的 base size **
- auto 默认值,具体所占的数值(100px)
决定 flex items 最终 base size 的因素,从优先级高到低
- max-width\max-height\min-width\min-height
- flex-basis
- width\height
- 内容本身的 size
.container {
background-color: aqua;
width: 200px;
height: 500px;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: flex-start;
}
.item {
width: 100px;
height: 100px;
border: 1px solid orange;
border-radius: 5px;
background: greenyellow;
box-sizing: border-box;
}
.flex-basis {
flex-basis: 140px;
}
<div class="container">
<span class="item flex-basis">item1</span>
<div class="item">item2</div>
<i class="item">item3</i>
</div>
6.flex
flex 只是 flex-grow || flex-shrink || flex-basis 的简写,具体用法请参考**概念篇**的使用
概念篇 遗留 问题解决
先来描述问题
问题是 当使用 多行排列时,当第二行的元素 少于第一行的元素, 第二行的flex item 不能和第一行的元素 上下对齐.
这里提供一种利用替补元素的方式解决问题. 通过给剩余位置补充等宽的i元素(但不设置高度),来达到布局的目的.
.container {
background-color: aqua;
width: 200px;
height: 200px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-around;
align-items: flex-start;
}
.item {
width: 50px;
height: 50px;
border: 1px solid orange;
border-radius: 5px;
background: greenyellow;
box-sizing: border-box;
}
.container > i {
width: 50px;
}
<div class="container">
<span class="item">item1</span>
<div class="item">item2</div>
<i class="item">item3</i>
<div class="item">item4</div>
<i class="item">item5</i>
<i class="item">item6</i>
<i class="item">item7</i>
<i class="item">item8</i>
<i class="item">item9</i>
<i class="item">item10</i>
<i class="item">item11</i>
<i class="item">item12</i>
<i class="item">item13</i>
<i></i><i></i><i></i>
</div>