你应该知道的 flex 布局

1,258 阅读7分钟

容器的属性

flex-direction

主轴和交叉轴 flex 布局是一种一维的布局,是因为一个 flexbox 一次只能处理一个维度的元素布局,一行或者一列。作为对比的是另外一个二维布局 CSS Grid Layout,可以同时处理行和列上的布局。

当使用 flex 布局时,首先想到的是两根轴线 — 主轴和交叉轴。主轴由 flex-direction 定义,另一根轴垂直于它。我们使用 flexbox 的所有属性都跟这两根轴线有关, 所以有必要在一开始首先理解它。

主轴和交叉轴由 flex-direction 定义,可以取4个值:

  • row
  • row-reverse
  • column
  • column-reverse

flex-direction: row 的时候,

flex-direction: row-reverse 的时候,

flex-direction: column 的时候,

flex-direction: column-reverse 的时候,

总结一下:flex-direction 主要改变了主轴的方向,而交叉轴要么是从上到下,要么是从左到右的。

flex-wrap

flex-wrap 属性指定 flex 元素单行显示还是多行显示。如果允许换行,这个属性允许你控制行的堆叠方向。

  • nowrap 默认取值,不换行,元素在一行显示
  • wrap 换行显示
  • wrap-reverse 换行显示,会使交叉轴开始和结束方向与 wrap 相反。

flex-direction: row; flex-wrap: wrap; align-items: flex-start; 的时候,

flex-direction: row; flex-wrap: wrap-reverse; align-items: flex-start; 的时候,

flex-wrap: wrap-reverse 是唯一能改变了交叉轴开始、结束方向的设置。

flex-flow

flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap

.box {
  flex-flow: <flex-direction> || <flex-wrap>;
}

justify-content

justify-content 属性定义了项目在主轴上的对齐方式。 如果主轴方向是从左向右,各属性的设置含义如下:

  • flex-start(默认值):左对齐
  • flex-end:右对齐
  • center: 居中
  • space-between:两端对齐,项目之间的间隔都相等。
  • space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。 image.png

align-items

align-items属性定义项目在交叉轴上如何对齐。如果交叉轴方向是从上到下,各属性的设置含义如下:

  • flex-start:交叉轴的起点对齐。
  • flex-end:交叉轴的终点对齐。
  • center:交叉轴的中点对齐。
  • baseline: 项目的第一行文字的基线对齐。
  • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。 image.png

注意: 当子元素设置了高度或者宽度的时候,align-items: stretch; 会失效,也就是 height/min-height/max-height 优先级高于 align-items: stretch;

.container{
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: stretch;
}
.item{
  width: 100px;
  height: 100px;
 }

align-content

align-content属性定义项目在交叉轴上如何对齐;如果项目只有一根轴线,该属性不起作用。如果交叉轴方向是从上到下,各属性的设置含义如下:

  • flex-start:与交叉轴的起点对齐。
  • flex-end:与交叉轴的终点对齐。
  • center:与交叉轴的中点对齐。
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
  • stretch(默认值):轴线占满整个交叉轴。

image.png

项目的属性

align-self

align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。用于设置单个项目在 交叉轴 上的对齐方式。

.container{
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-start;
}
.item:nth-child(1){
  align-self: flex-end;
}

flex-grow

flex-grow 表示在主轴方向上,如果子项目的宽度和(或者高度和)并没有完全占满 flex 父容器的宽度,父容器剩余宽度将如何分配。flex-grow 默认是0,即不拉伸子容器,即使父容器没有被占满,如下:

 .container{
  width: 550px;
  height: 250px;
  border: 5px solid silver;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-start;
}
.item{
  width: 100px;
  height: 100px;
  background-color: blueviolet;
}

flex-grow 一般取数字,表示占分配父容器剩余宽度(高度)的份数,如下:

.item:nth-child(1){
  flex-grow: 1
}
.item:nth-child(2){
  flex-grow: 2
}
.item:nth-child(3){
  flex-grow: 2
}

表示如果父容器宽度还有剩余,则第一个元素占 1 份,第二个元素占 2 份,第三个元素占 2 份。计算如下:

父元素剩余宽度:550 - 100 - 100 - 100 = 250
总份数:1 + 2 + 2 = 5
每份占的宽度:250/5 = 50
第一个子元素宽度:50*1 + 100 = 150
第二个子元素宽度:50*2 + 100 = 200
第三个子元素宽度:50*2 + 100 = 200

flex-shrink

flex-shrink 表示在主轴方向上,如果子项目的宽度和(或者高度和)超过 flex 父容器的宽度,子项目会不会缩小。flex-shrink 默认为1,即如果空间不足,该项目将缩小。

.container{
  width: 550px;
  height: 250px;
  border: 5px solid silver;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-start;
}
.item{
  width: 200px;
  height: 100px;
}
.item:nth-child(1){
  flex-shrink: 1
}
.item:nth-child(2){
  flex-shrink: 2
}
.item:nth-child(3){
  flex-shrink: 2
}

表示如果父容器被超过时,则第一个元素缩小占 1 份,第二个元素缩小占 2 份,第三个元素缩小占 2 份。计算如下:

父元素超过的宽度:200 + 200 + 200 - 550 = 50
每份占的宽度:50/(200*1 + 200*2 + 200*2) = 0.05
第一个子元素宽度:200 - 1*0.05*200 = 190
第二个子元素宽度:200 - 2*0.05*200 = 180
第三个子元素宽度:200 - 2*0.05*200 = 180

flex-basis

flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

优先级:min-width/max-width > flex-basis > width

.item{
  width: 200px;
  height: 100px;
}
.item:nth-child(1){
  flex-basis: 50px;
}
.item:nth-child(2){
  flex-basis: 50px;
  min-width: 100px;
}
.item:nth-child(3){
  flex-basis: 150px;
  max-width: 100px;
}

flex

flex属性是flex-growflex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。

建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。

面试常问:flex: 1 什么含义?

在 Chrome 浏览器下:
image.png

order

order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。

.container{
  width: 550px;
  height: 550px;
  display: flex;
  flex-direction: column;
}
.item{
  width: 200px;
  height: 100px;
}
.item:nth-child(1){
  order: 1
}

一些技巧

margin 自动撑满

image.png 实现头像靠右对齐,可以利用 flex 弹性布局 + margin 实现:

.container{
  width: 850px;
  display: flex;
  align-items: center;
}
.item{
  width: 200px;
  height: 80px;
  line-height: 80px;
}
.circle{
  width: 50px;
  height: 50px;
  border-radius: 50%;
  margin-left: auto;   // 关键代码
}
  <div class="container">
    <div class="item">首页</div>
    <div class="item">菜单1</div>
    <div class="circle"></div>
  </div>

水平垂直居中

.container{
  display: flex;
  justify-content: center;
  align-items: center;
  width: 300px;
  height: 200px;
  border: 1px solid black;
}
<div class="container">文本居中</div>

栅格平分

image.png 左右间距是 10px,距离下面边距也是 10px;元素一行 4 个,所以宽度是 25%。

  <style>
  .container{
    width: 900px;
    display: flex;
    flex-wrap: wrap;
    border: 1px solid black;
    padding-bottom: 10px;
  }
  .item{
    width: 25%;
    padding: 0 10px;
    margin-top: 10px;
    box-sizing: border-box;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .search{
    width: 100%;
  }
  </style>
<body>
  <div class="container">
    <div class="item"><input class="search" /></div>
    <div class="item"><input class="search" /></div>
    <div class="item"><input class="search" /></div>
    <div class="item"><input class="search" /></div>
    <div class="item"><input class="search" /></div>
  </div>
</body>
</html>

参考推荐:
Flex 布局教程:语法篇
原来flex布局还能那么细?