flex实战

2,421 阅读11分钟

前言我也不知道怎么写,那废话就不多说了,反正flex布局不考虑兼容性的话用处还是挺多的,个人感觉也是挺神奇挺好用的。在平时的工作中,flex发挥了非常大的作用,今天就来总结一下吧。

语法介绍

这里只介绍我常用的flex属性,有不足的地方欢迎指正(以下情况默认都是在浏览器的默认属性基础上进行介绍)

启用flex布局

display: flex;

这个想必大家都非常熟悉了,我也就不多说了。

布局方向

flex-direction: row; // 浏览器默认布局方式,在同一行内进行排列(flex-wrap: nowrap的情况下)

flex-direction: column; // 在同一列内进行排列,类似于常规的一行一行的排列

至于row-reversecolumn-reverse就不说了,感觉应用场景不多。

对齐方式

这里就需要认识一下主轴(main axis)和交叉轴(cross axis)

简单地说主轴就是排列方向,交叉轴和排列方向相垂直。

具体地说:flex-direction: row;时,主轴是指水平方向,交叉轴是垂直方向。flex-direction: column;时,主轴是指垂直方向,交叉轴是水平方向。

用图来表示的话就是:

主轴

交叉轴

主轴对齐

justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
  1. flex-start 靠左对齐(row)或是靠上对齐(column)
  2. flex-end 靠右对齐(row)或是靠下对齐(column)
  3. center 居中对齐
  4. space-between 两边对齐,项目之间的间隔都相等(常用
  5. space-around 两边对齐,但跟 space-between 不同的是,它在两侧各有 1/2 的间距(不常用
  6. space-evenly 两边对齐,两侧各有 1 倍的间距(看的别人的介绍,不知道有什么实际用途,只知道两边的空白比space-around大)

交叉轴对齐


align-items: flex-start | flex-end | center | baseline | stretch;
  1. flex-start 靠上对齐(row)或是靠左对齐(column)
  2. flex-end 靠下对齐(row)或是靠右对齐(column)
  3. center 居中对齐
  4. baseline: 项目的第一行文字的基线对齐;
  5. stretch(默认值)如果项目未设置宽度/高度或设为auto并且flex-wrap: nowrap;(未设置时默认就是nowrap),将占满整个容器的高度(row)/宽度(column)

交叉轴和主轴不一样,可没有什么两端对齐,所以可千万别混淆了。

单行时使用 align-items, 多行时使用align-content, 这两种都是使用于display: flex的元素,而align-self可以单独设置子元素的交叉轴对齐方式

是否换行

flex-wrap: nowrap | wrap | wrap-reverse;

当使用nowrap时,当子元素的宽度之和超过父元素的宽度时并不会换行,而是尽量压缩自身以保障不超过父元素的宽度,所以有时候你会发现flex内的子元素宽度跟你想象的不一样就是这个原因造成的。

至于宽度到底是怎么计算的嘛,说来还是有点复杂的。理论上, 当子元素的宽度之和超过父元素的宽度时,子元素的宽度 = 子元素所设置的宽度 / 子元素之和 父元素的宽度。

假设父元素是100px,子元素A是100px,B是400px,C元素是500px,那么理论上子元素之和为1000px,A = 100 / 1000 * 100 = 10px,B = 400 / 1000 * 100 = 40px, C = 500 / 1000 * 100 = 50px。

当然了,这只是理论上的理想情况。实际上,能不能按照理论分配,还得看子元素内的实际宽度,什么是实际宽度呢?就是它里面的内容所占的宽度,假设A里面的文字有3个,占用了25px,那么它的最终宽度就是25px,而不是所分配的10px,B和C也会相应的减少。

使用wrap的话就不会存在这个问题了,在一定程度上可以替代之前的inline-block和float的布局方式。

flex-grow

flex: 1;
/*
其实就相当于
    flex-grow: 1;
    flex-shrink: 1;
    flex-basis: 0%;
*/

这个属性的作用就是将剩余宽度按照比例分配给该子元素。常用于两栏布局,一侧定宽,另一侧设置flex: 1;即可获得剩余宽度。

排列顺序order

order: 1; /* 任意正整数 */

这个东西可是很神奇的了,不需要改变html的结构,直接改变显示的顺序,比如常见的列表介绍,第一行左图右文字,第二行左文字右图。

还有一种应用场景就是聊天界面了,这个稍后会讲到。

总算是讲完基础部分,接下来终于可以进入今天的正题了。

实战部分

居中

这个应该是最常遇到的布局方式了吧,主要分为单行居中,多行居中。

单行居中

其实这里还分为只有一行的元素水平居中和多行中的某一行水平居中两种情况,暂时只介绍第一种情况,下一段再介绍后一种情况。

<div class="flex-center" style="background: red;color: #fff;padding: 20px 0;">
    单行水平居中
</div> 
.flex-center {
  display: flex;
  flex-direction: row;
  justify-content: center;
}

排列方向为row的情况设置主轴对齐方式为center即可,没什么好说的。

多行居中(换行时)

可以看到在使用flex-wrap: wrap后,align-content: center是将所有的子元素组合成一个整体后垂直居中,而align-content: center则是将剩余部分的空白平均分配给子元素的上下两侧。所以这种换行后的多行垂直居中推荐大家使用align-content

<div class="attr-title">align-content: center</div>
<div class="flex box" style="align-content: center;">
    <div class="red">red</div>
    <div class="green">grren</div>
    <div class="blue">blue</div>
</div>

<div class="attr-title">align-items: center</div>
<div class="flex box" style="align-items: center;">
    <div class="red">red</div>
    <div class="green">grren</div>
    <div class="blue">blue</div>
</div>
.flex {
  display: flex;
  flex-direction: row;
}
.red {
  background: red;
  width: 50%;
  height: 30px;
}
.green {
  background: green;
  height: 40px;
  width: 100%;
}
.blue {
  background: blue;
  width: 100%;
}
.attr-title {
  margin-top: 24px;
  margin-bottom: 12px;
}
.box {
  border: 5px solid #ccc;
  flex-wrap: wrap;
  height: 200px;
}

多行居中(column)

代码如下:

<div class="attr-title">flex-direction: column 垂直居中</div>
  <div class="flex-center column border">
    <div class="red">red</div>
    <div class="green">grren</div>
    <div class="blue">blue</div>
  </div>
.flex-center {
  display: flex;
  flex-direction: row;
  justify-content: center;
}
.column {
  flex-direction: column;
}
.border {
  border: 5px solid #ccc;
  height: 200px;
}

多行垂直居中的话,相比较上面换行的那种,还是推荐大家使用column这种方式。毕竟代码简洁,更好理解。还有很重要的一点就是可以更灵活的控制子元素在水平方向的对齐方式,在文章的排版中应该会比较常见。

可能有的人会说这种排版使用text-align也能办到。确实也可以,但是text-align只能作用于块级元素,而flex布局则没有这个局限性。

<div class="flex column">
    <h2 class="title self-center">黑洞的发现</h2>
    <div class="flex between">
      <div class="author">某网站</div>
      <time class="time self-end">发布时间:2019-04-12</time>
    </div>
    <article class="article">
      <p>正文中打撒打撒打撒多撒正文中打撒打撒打撒多撒正文中打撒打撒打撒多撒</p>
    </article>
</div>
.flex {
  display: flex;
  flex-direction: row;
}
.column {
  flex-direction: column;
}
.between {
  justify-content: space-between;
}
.self-center {
  align-self: center; 
}
.self-end {
  align-self: flex-end; 
}
.author {
  font-size: 14px;
  color: #666;
}
.time {
  color: #999;
  font-size: 12px;
}
.article p {
  text-indent: 2em;
  line-height: 1.6;
}

两端对齐

这个应用场景也挺多的,比如左侧是标题,右侧是更多>>。原理也很简单,就是

.flex {
  display: flex;
  flex-direction: row;
}
.between {
  justify-content: space-between;
}

在需要两端对齐的时候,只需要在父元素加上这两个类名就可以了。效果图就不上了,上方文章排版的那个就用到了。

多栏布局

这里只举例最简单的两栏布局,其他的类似,自己推导即可。

在应用flex以后,左侧定宽,右侧flex: 1;即可获得剩余宽度。

<div class="flex">
    <div class="red">red</div>
    <div class="green">grren</div>
</div>
.flex {
  display: flex;
  flex-direction: row;
}
.red {
  width: 100px;
  background: red;
  height: 36px;
}
.green {
  flex: 1;
  background: green;
}

不知道大家有没有发现,上图中我只设置了red的高度,但是green的高度居然和red的一致!平时的布局中不是只有文字的高度吗?

其实这就是上文所说的自动填充高度了,align-items: stretch会将未主动设置高度的子元素拉伸至与高度最高的子元素相同。align-items的默认值就是stretch,所以如果不需要自动填充高度,你需要设置align-items为flex-start,flex-end,center等其他的值。

order简单运用

有了order以后,就可以在不改变html结构的情况下,通过改变order的数值来改变子元素的显示顺序。

分析一下这个布局,其实也就是两栏布局,然后文字部分垂直居中,前面都介绍过了,所以实现起来是很简单的。

代码如下:

<ul class="list">
    <li class="flex item even">
      <img src="https://taidaxin.oss-cn-qingdao.aliyuncs.com/1.jpg" alt="" class="img">
      <div class="content flex-center column">
        <div class="p">介绍</div>
        <div class="p">flex布局</div>
      </div>
    </li>
    <li class="flex item odd">
      <img src="https://taidaxin.oss-cn-qingdao.aliyuncs.com/1.jpg" alt="" class="img">
      <div class="content flex-center column">
        <div class="p">介绍</div>
        <div class="p">flex布局</div>
      </div>
    </li>
</ul>
.flex {
  display: flex;
  flex-direction: row;
}
.flex-center {
  display: flex;
  flex-direction: row;
  justify-content: center;
}
.column {
  flex-direction: column;
}
.list {
  padding: 20px;
  background: #F5F5F5;
}
.img {
  width: 94px;
  height: 94px;
}
.item+.item {
  margin-top: 20px;
}
.content {
  padding-left: 20px;
  background: #fff;
  font-size: 12px;
  flex: 1;
}
.even .img,
.odd .content {
  order: 1;
}
.even .content,
.odd .img {
  order: 2;
}

卡片式布局

卡片式布局这个就很有综合性了,先来分析下布局吧。

  • 首先分为图片和主体上下两部分
  • 主体又分为左右两栏布局
  • 左栏按照普通的布局来就行
  • 右栏占据剩余宽度,设置flex: 1;,上下两端对齐,靠右对齐,那么可以采用使用column的布局方式,主轴两端对齐,交叉轴对齐于结尾处,表现为justify-content: space-between;align-items: flex-end;

代码如下:

<div class="container">
    <div class="card">
      <img src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png" alt="" class="card-img">
      <div class="card-body flex">
        <div class="card-body--left">
          <div class="title">标题</div>
          <div class="text">发布者:谁知道</div>
          <time class="time">栏目:天知道</time>
        </div>
        <div class="card-body--right flex column between">
          <div class="share flex align-center">
            <img src="http://uppic.fd.zol-img.com.cn/t_s501x2000/g5/M00/0D/0D/ChMkJ1ibsVeIeZ0QAACr6Uwo-6EAAZzpgMdtPAAAKwB105.jpg" alt="" class="share-icon">
            <div class="share-text">分享</div>
          </div>
          <time class="time">发布时间: 2019-01-02</time>
        </div>
      </div>
    </div>
</div>
.flex {
  display: flex;
  flex-direction: row;
}
.between {
  justify-content: space-between;
}
.flex-center {
  display: flex;
  flex-direction: row;
  justify-content: center;
}
.column {
  flex-direction: column;
}
.container {
  background: #F5F5F5;
  padding: 32px;
}
.card {
  width: 320px;
  margin: 20px auto;
}
.card-img {
  width: 100%;
}
.card-body {
  padding: 20px;
  background: #fff;
}
.title {
  font-size: 16px;
  color: #333;
}
.text {
  font-size: 14px;
  color: #666;
  padding: 8px 0;
}
.card-body--right {
  flex: 1;
  align-items: flex-end;
}
.time {
  font-size: 12px;
  color: #999;
}
.share {
  align-items: center;
}
.share-icon {
  width: 40px;
  height: 40px;
}

聊天界面

简单的分析一下布局,一个别人发的,一个自己发的,也就靠左和靠右对齐的区别而已。

从正常的布局来看,先是头像,然后是一个三角形的箭头(用border即可),再然后就是对话内容了。 反方向的话,就是控制一下这三个部分的order而已,还有就是外边距的方向也得反一下。

跟之前的东西相比没有什么新鲜的,我就不贴代码了,要不然就太多了,当然了有需要的话可以留言,我可以放在评论区。

平时布局的话,大家还是要注意多总结,先思考怎么布局更简单,然后再着手写代码,这样可以省下很多时间的。flex在一维布局确实是很强大的,基本上可以解决平时遇到的各种问题。grid在二维布局方面相对而言更好用,都怪这**的兼容性问题,要不然我们就有更多更好的方式可以选择了。

那么今天就先说到这里吧(虽然大部分都是代码),如果大家还有什么疑问或者指导性建议的话,欢迎评论。