css-flex布局

521 阅读12分钟

flex

Flex是Flexible Box的缩写,意为弹性布局,可以为盒模型提供最大的灵活性。

任何一个容器都可以是flex布局。

.box{
    display:flex;
}

注意:使用flex布局后,子元素的float,clear,vertical-align属性将失效。

基本概念

设置了flex布局的元素,称为flex-container容器,它的所有子元素称作容器成员,flex-item。

容器有两根轴:水平主轴main-axis和垂直的交叉轴cross-axis。

我们来简单的写一个flex布局容器,box容器只设置宽度,不设置高度。子元素高宽100px显示。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>flex布局</title>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src='js/jquery.min.js'></script>
  <style>
    .box{
      margin:50px auto;
      width:1400px;
      border:3px solid #ce7f3b;
    }
    .box-item{
      width:100px;
      height:100px;
      line-height: 100px;
      margin:10px;
      font-size:32px;
      color:white;
      text-align: center;
    }
    .flex{
      display: flex;
    }
    .flex-direction{
      flex-direction: row;
    }
    .green{
      background:green;
    }
    .blue{
      background: deepskyblue;
    }
    .yellow{
      background: yellowgreen;
    }
    .red{
      background: red;
    }
    .orange{
      background: orange;
    }
  </style>
</head>
<body>
<div id="app">
  <div class="box flex flex-direction">
    <div class="box-item green">1</div>
    <div class="box-item blue">2</div>
    <div class="box-item yellow">3</div>
    <div class="box-item red">4</div>
    <div class="box-item orange">5</div>
  </div>
</div>
<script>
  var app = new Vue({
    el: '#app'
  })
</script>
</body>
</html>

容器属性

它有六个属性

  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content

flex-direction

flex-direction决定主轴的方向,即子元素排列的方向。

它有四个值:

 flex-direction: row | row-reverse | column | column-reverse;
  • row:默认值,主轴在水平方向,起点在左端

我们给box容器加上类flex-direction,并将它的值设置为row

<style>
    .flex-direction{
      flex-direction: row;
    }
</style>
<div class="box flex flex-direction"></div>

效果如图:

  • row-reverse:主轴在水平方向,起点在右端
<style>
    .flex-direction{
      flex-direction: row-reverse;
    }
</style>
<div class="box flex flex-direction"></div>

效果如图:

  • column:主轴在垂直方向,起点在上沿
<style>
    .flex-direction{
      flex-direction: column;
    }
</style>
<div class="box flex flex-direction"></div>

效果如图:

  • column-reverse:主轴在垂直方向,起点在下沿
<style>
    .flex-direction{
      flex-direction: column-reverse;
    }
</style>
<div class="box flex flex-direction"></div>

效果如图:

flex-wrap

默认情况下,无论flex容器的宽度是多大,子元素都会排列在一条线上。如果flex容器的宽度小于所有子元素宽度的总和,那么子元素的宽度就会按比缩小,以至适应flex容器。

例如:我们把上述flex容器的宽度变为400px;

.box{
    width:400px;
}

效果如图:

如果我们想并不想压缩子元素的宽度,想换行,该怎么做?

flex-wrap决定是否换行显示以及换行之后子元素的排列方式。

它有三个值:

 flex-wrap: nowrap | wrap | wrap-reverse;
  • nowrap:默认值,不换行

我们给box容器加上类flex-wrap,并将它的值设置为row

<style>
    .flex-wrap{
      flex-wrap: row;
    }
</style>
<div class="box flex flex-wrap"></div>

效果如上。

  • wrap:换行,第一行在上方
<style>
    .flex-wrap{
      flex-wrap: wrap;
    }
</style>
<div class="box flex flex-wrap"></div>

效果如图:

  • wrap-reverse:换行,第一行在下方
<style>
    .flex-wrap{
      flex-wrap: wrap-reverse;
    }
</style>
<div class="box flex flex-wrap"></div>

效果如图:

flex-flow

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

.flex-flow{
    flex-flow: row nowrap;
}

justify-content

justify-content定义了子元素在主轴上的对齐方式。

它有五个值:

justify-content: flex-start | flex-end | center | space-between | space-around;

这里我们先把每个子元素的宽度改一下,改为不同的宽度。flex容器宽度改为1000px。

.box{
    width:1000px;
}
   .box-item.green{
      width:50px;
    }
    .box-item.blue{
      width:100px;
    }
    .box-item.yellow{
      width:150px;
    }
    .box-item.red{
      width:200px;
    }
    .box-item.orange{
      width:250px;
    }
  • flex-start:左对齐

我们给box容器加上类justify-content,并将它的值设置为flex-start

<style>
    .justify-content{
      justify-content: flex-start;
    }
</style>
<div class="box flex justify-content"></div>

效果如图:

  • flex-end:右对齐
<style>
    .justify-content{
      justify-content: flex-end;
    }
</style>
<div class="box flex justify-content"></div>

效果如图:

  • center:居中
<style>
    .justify-content{
      justify-content: center;
    }
</style>
<div class="box flex justify-content"></div>

效果如图:

  • space-betwwen:两端对齐,子元素之间的间隔相等
<style>
    .justify-content{
      justify-content: space-betwwen;
    }
</style>
<div class="box flex justify-content"></div>

效果如图(为了直观感受,我把子元素的margin左右边距置为0):

  • space-around:每个子元素两侧的间隔相等

项目之间的间隔比项目与边框的间隔大一倍。

<style>
    .justify-content{
      justify-content: space-betwwen;
    }
</style>
<div class="box flex justify-content"></div>

效果如图,可以看到,绿方块和蓝方块之间的距离,刚好是绿方块和容器边框距离的两倍。

align-items

align-items定义了子元素在交叉轴上的对齐方式。

它有五个值,具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下

交叉轴的方向与flex-direction的值有关。如果主轴为水平,交叉轴则为垂直,如果主轴为垂直,交叉轴为水平方向。

align-items: flex-start | flex-end | center | baseline | stretch;

为了直观感受,我们再把子元素的宽度改为相等,高度不一致。

.box-item.green{
      height:50px;
    }
    .box-item.blue{
      height:100px;
    }
    .box-item.yellow{
      height:150px;
    }
    .box-item.red{
      height:200px;
    }
    .box-item.orange{
      height:250px;
    }
  • flex-start:交叉轴的起点对齐

我们给box容器加上类align-items,并将它的值设置为flex-start

<style>
    .align-itemst{
      align-items: flex-start;
    }
</style>
<div class="box flex align-items"></div>

效果如图:

  • flex-end:交叉轴的终点对齐
<style>
    .align-itemst{
      align-items: flex-end;
    }
</style>
<div class="box flex align-items"></div>

效果如图:

  • center:交叉轴的中点对齐
<style>
    .align-itemst{
      align-items: center;
    }
</style>
<div class="box flex align-items"></div>

效果如图:

  • baseline:子元素的第一行文字的基线对齐
<style>
    .align-itemst{
      align-items: baseline;
    }
</style>
<div class="box flex align-items"></div>

效果如图:

  • stretch:如果子元素未设置高度或设为auto,将占满整个容器的高度

我们这里把所有子元素的高度设置为auto。flex容器的高度置为400px。

.box{
    height:400px;
}
.box-item.green,.box-item.blue, .box-item.yellow,.box-item.red,.box-item.orange{
      height:auto;
    }
<style>
    .align-itemst{
      align-items: baseline;
    }
</style>
<div class="box flex align-items"></div>

效果如图:

align-content

align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

多根轴线跟flex-wrap的取值有关,如果子元素换行显示,则存在多根轴线,如果不换行,则只有一根轴线。

它有六个值

align-items: flex-start | flex-end | center | baseline | stretch;

为了直观感受,我们多增加几个颜色方块,每个方块的高度相等,宽度不一致。设置容器宽度为400px,flex-wrap设置为换行。

<style>
.box{
    height:400px;
}
.orange2{
      background: palegoldenrod;
    }
    .orange3{
      background: palegreen;
    }
    .orange4{
      background: palevioletred;
    }
    .orange5{
      background: purple;
    }
    .orange6{
      background: peru;
    }
    .box-item.green{
      width:50px;
    }
    .box-item.blue{
      width:100px;
    }
    .box-item.yellow{
      width:150px;
    }
    .box-item.red{
      width:200px;
    }
    .box-item.orange{
      width:250px;
    }
      .box-item.orange2{
      width:50px;
    }
    .box-item.orange3{
      width:100px;
    }
    .box-item.orange4{
      width:150px;
    }
    .box-item.orange5{
      width:200px;
    }
    .box-item.orange6{
      width:250px;
    }
    .flex-wrap{
        flex-wrap:wrap;
    }
</style>
<div class="box flex flex-wrap align-content">
    <div class="box-item green">1</div>
    <div class="box-item blue">2</div>
    <div class="box-item yellow">3</div>
    <div class="box-item red">4</div>
    <div class="box-item orange">5</div>
    <div class="box-item orange2">6</div>
    <div class="box-item orange3">7</div>
    <div class="box-item orange4">8</div>
    <div class="box-item orange5">9</div>
    <div class="box-item orange6">10</div>
  </div>
  • flex-start:交叉轴的起点对齐

我们给box容器加上类align-content,并将它的值设置为flex-start

<style>
    .align-content{
      align-content: flex-start;
    }
</style>
<div class="box flex align-content"></div>

效果如图:

  • flex-end:交叉轴的终点对齐

如果flex容器没有设置高度,值flex-start,flex-end作用相同。

<style>
    .align-content{
      align-content: flex-end;
    }
</style>
<div class="box flex align-content"></div>

效果如图:

  • center:交叉轴的中点对齐
<style>
    .align-content{
      align-content: center;
    }
</style>
<div class="box flex align-content"></div>

效果如图:

  • space-between:与交叉轴的两端对齐,轴线之间的间隔相等
<style>
    .align-content{
      align-content: space-between;
    }
</style>
<div class="box flex align-content"></div>

效果如图:

  • space-around:每根轴线两侧的间隔都相等
<style>
    .align-content{
      align-content: space-around;
    }
</style>
<div class="box flex align-content"></div>

效果如图:

  • stretch:默认值,轴线沾满整个交叉轴

子元素没有设置高度或者高度为auto的情况下,会沾满容器,如果设置了,则显示子元素原本高度。

<style>
    .align-content{
      align-content: stretch;
    }
</style>
<div class="box flex align-content"></div>

效果如图:

子元素即项目属性

子元素有六个属性

  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • flex
  • align-self

order

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

.box-item{
    order:1
}

flex-grow

flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。

如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

.box-item{
    flex-grow:1
}

flex-shrink

flex-shrink属性定义了子元素的缩小比例,默认为1,即如果空间不足,该子元素将缩小。

.box-item {
  flex-shrink: <number>; /* default 1 */
}

如果所有子元素的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个子元素的flex-shrink属性为0,其他子元素都为1,则空间不足时,前者不缩小。

负值对该属性无效。

flex-basis

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

它可以设为跟width或height属性一样的值(比如350px),则子元素将占据固定空间。

.box-item {
  flex-basis: <length> | auto; /* default auto */
}

flex属性

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

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

align-self属性

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

.box-item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

总结

有一次面试,面试官问了我一个问题:一个页面中有很多div1,div2,div3..divn,从上到下排列,有什么方法,用css布局,能让这些div反转,变成divn..div3,div2,div1。

想了片刻,没想出什么果子。

后来,面试官提了提flex布局,作为小白的我,当然只是稍微了解一点,说又说不出来个啥。emmmm.....

自己动手总结,丰衣足食。

面试题:一个页面中有很多div1,div2,div3..divn,从上到下排列,有什么方法,用css布局,能让这些div反转,变成divn..div3,div2,div1?

利用flex-direction属性改变主轴方向,并且反转。

<style>
.box{
    display:flex;
    flex-direction:column-reverse;
}
</style>
<div class="box">
 <div>1</div>
 <div>2</div>
 <div>3</div>
</div>

面试题:如何让项目内容宽度等分?

利用子元素的放大比例属性flex-grow。

<style>
.box{
    display:flex;
}
.box div{
    flex-grow:1;
}
</style>
<div class="box">
 <div></div>
 <div></div>
 <div></div>
</div>

面试题:左右布局,一侧定宽,一侧自适应撑满

利用子元素的放大比例属性flex-grow,设置为1,让右布局自适应。

<style>
.box{
    display:flex;
}
.box.left{
    flex-basis:300px;
}
.box.right{
    flex-grow:1;
}
</style>
<div class="box">
 <div class="left">固定</div>
 <div class="right">自适应宽度</div>
</div>

面试题:未知高宽,水平垂直居中

<style>
.box{
    display:flex;
    align-items:center;
    justify-content:center;
}
</style>
<div class="box">
 <div>垂直水平居中</div>
</div>

面试题:在一个横向布局上,假设有三个div,每个宽度为定宽apx,如果想使两侧宽度为x,中间div间间隔为2x。x可以自适应。

<style>
.box{
    display:flex;
    justify-content:space-around;
}
</style>
<div class="box">
 <div class="left">1</div>
 <div class="center">2</div>
 <div class="right">3</div>
</div>