Flex box styles in CSS

可能是自己对Flex box的全部理解了。

Background

Flex box,也叫”弹性盒子“,目的是更高效的创建布局、对齐方式、动态处理剩余空间等问题。

在Flex box之前,float和position被广泛的使用在布局里面,但是处理以下三个问题时会非常棘手:

  • 在父容器里垂直居中一个块元素

  • 动态设置子项等量宽度/高度,无论还有多少剩余空间。

  • 多列布局中所有子项高度相同,而不管子项实际内容

对于以上问题,Flex box处理起来可谓是得心应手,而现在各浏览器对于flex box的支持也很好了,点击Can I Use链接查看是否支持,所以,使用flex box会帮助我们更快地解决问题,提升开发效率和可维护性。

当然,flexbox并不是万能的,搭配position使用效果更佳!

Basics and Terminology

  • 容器(Container)项(item)

  • 容器有两个轴,主轴(main axis)和交叉轴(cross axis),默认主轴是水平方向,交叉轴永远和主轴垂直,正方向是向右或者向下,reverse方向是向左或者向上。

  • 可以随意安排子项,顺序而不用改变文档结构。

  • 对于容器和项,有不同的职责和属性。

  • flex box是方向无关的,对比HTML元素,div等块级元素默认是垂直排列的,span等内联元素默认是水平排列的

Flex Box

Flex容器属性

1
2
3
.container {
flex-direction: row | row-reverse | column | column-reverse;
}
1
2
3
.container {
flex-wrap: nowrap | wrap | wrap-reverse;
}
  • flex-flow: flex-directionflex-wrap 的简写形式
1
2
3
.container {
flex-flow: <flex-direction> || <flex-wrap>;
}
1
2
3
.container {
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}

space-around: 每个item等分空间,然后每个item的左右相等,也就是说两个item中间的空间是最左/右侧空间的两倍。

space-between: 两侧item紧挨着边界,中间剩余空间平分。

space-evenly: 剩余空间数量为item的数量+1,均分。

1
2
3
.container {
align-items: stretch | center | flex-start | flex-end;
}
1
2
3
.container {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

注意: 仅当存在多轴线时有效!也就是说 flex-wrap为nowrap的时候,不会产生多线,这个效果也就没用。

Flex项属性

  • align-self: 设置单个项和其他项不同排列方式
1
2
3
.item {
align-self: stretch | flex-start | flex-end | center;
}

会覆盖align-items属性。

  • order: 在同一容器内重新排列元素顺序,值为整数
1
2
3
.item {
order: <integer>
}
1
2
3
.item {
flex-grow: <integer>
}

当所有项初始化之后,还有剩余空间时,flex-grow才会生效;

默认值为0,即即使存在剩余空间,也不会放大;

如果存在剩余空间,容器内所有设置flex-grow的项根据权重进行分配剩余空间;

如果所有项以flex-basis排列后,主轴空间不足,并且flex-wrap: nowrap时,需要配合flex-shrink使用。

1
2
3
.item{
flex-shrink: <positive-number>
}

缩小方式和放大方式类似。

那么问题来了: 缩小后的值是多少?计算方式是什么?

Stack Overflow链接,能否看懂就看各位的造化了…

我说几句自己的理解:缩小算法和缩小因子因子有关,也和所有的项的flex-basis的和与父容器width(或者height,取决于flex-direction)的差值大小有关,总之是一个比较复杂的计算方式,对于不能FQ的朋友们,我把原作者的解释代码放在下面👇,供大家参考学习。

算法👇

1
2
3
4
5
6
7
8
9
10
11
let sumScaledShrinkFactors = 0,
remainingFreeSpace = flexContainer.innerMainSize;
for (let item of flexItems) {
remainingFreeSpace -= item.outerFlexBasis;
item.scaledShrinkFactor = item.innerFlexBasis * item.flexShrinkFactor;
sumScaledShrinkFactors += item.scaledShrinkFactor;
}
for (let item of flexItems) {
let ratio = item.scaledShrinkFactor / sumScaledShrinkFactors;
item.innerWidth = item.innerFlexBasis + ratio * remainingFreeSpace;
}

公式👇

1
flexBasis * (1 + shrinkFactor / sumScaledShrinkFactors * remainingFreeSpace)

例子👇

1
2
3
4
5
6
1*600px + 1*200px ─┐               width
│ ───────
600px * (1 + 1 / 800px * -200px) = 450px
200px * (1 + 1 / 800px * -200px) = 150px
│ ───────
600px - (600px + 200px) ────┘ 600px
1
2
3
.item {
flex-basis: auto | <width>
}

flex-basis设置了值之后,项的width or height(取决于主轴方向,主轴方向的值)会失效;

当设置为auto时,项的width or height才会生效。

  • flex: flex-growflex-shrinkflex-basis的简写
1
2
3
.item {
flex: auto | none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

两个快捷值: auto(1 1 auto)none(0 0 auto);

flex-growflex-shrink不会同时起作用;

flex项如果flex-growflex-shrink都设置了,无论flex-wrapwrap还是nowrap,所有的项就会撑满容器,也就是说,只要有剩余空间,flex-grow就会起作用,只要空间不足,flex-shrink就会起作用。

Reference

Code Repository

示例内容详见GitHub Link