常见瀑布流及最佳实践

2023/02/02

背景

瀑布流布局在我们现在的前端页面中经常会用的到,有很多优点

  1. 节省页面空间
  2. 方便下拉刷新、到底加载等操作
  3. 让用户有向下浏览的冲动
  4. 布局美观,错落有致
  5. 移动端友好

介绍当前各大网站常见的图片瀑布流形式

各种瀑布流及实现

1. 元素宽高均相同 & 列数固定

最简单的图片布局方案,每张图片等宽等高展示,图片按比例进行裁切,列数固定。常用于社交网站。

参考网站:Instagram

waterfall-ins.png

优点:

  • 图片不变形
  • 各个图片展示面积相同
  • 行高相同
  • 可按照原始顺序输出
  • 整体布局整齐

缺点:

  • 不能保证完全展示图片内容
  • 非响应式

实现方式:

  1. 由于不能保证完全展示图片内容,为避免图片拉伸,使用 object-fit: cover 裁切图片
  2. 给每张图片设定 固定宽度 之后使用 flex 布局即可
  3. 解决最后一行展示问题
.container {
  width: 1000px;
  margin: 0 auto;
  overflow: hidden;
  border: 1px solid darkgray;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;

  div {
    width: 247px; // 固定宽高
    height: 247px;
    margin-bottom: 4px;

    // 最后一行三个元素的情况
    &:last-child:nth-child(4n - 1) {
      margin-right: 251px
    }

    // 最后一行两个元素的情况
    &:last-child:nth-child(4n - 2) {
      margin-right: 502px;
    }
  }

  img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

2. 元素宽高均相同 & 列数自适应

上一种布局的增强版,在上一种布局的基础上使得列数不在固定,因此可以适应各种大小屏幕。容器放大缩小的时候图片大小也会跟随变化,图片有最小的显示宽度,如果当前列数下,图片一行展示不下,则自动减少列数。常用于图站索引页。

参考网站:google photos 探索页500px

waterfall-google.png

优点:

  • 图片不变形
  • 各个图片展示面积相同
  • 行高相同
  • 可按照原始顺序输出
  • 整体布局整齐

缺点:

  • 不能保证完全展示图片内容

实现方式:

  1. 由于不能保证完全展示图片内容,为避免图片拉伸,使用 object-fit: cover 裁切图片
  2. 先考虑宽度问题:使用 flex 布局使容器宽度自适应,并设置最小宽度,当前的显示列数就等于 整体宽度/最小值 ,剩余部分会自动撑大
  3. 再考虑高度问题:由于需要让宽高比例固定,而宽度又是不确定的,故使用 padding-bottom 固定容器比例,因为 padding 的百分比是基于父容器的宽度决定的。可参考这个 demo
  4. 解决最后一行展示问题,尾部添加额外标签占满最后一行
.container {
  width: 100%;
  margin: 0 auto;
  overflow: hidden;
  border: 1px solid darkgray;
  display: flex;
  flex-wrap: wrap;

  div {
    flex: 1 0 250px;
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
    margin: 2px;
    position: relative;
    overflow: hidden;

    &:after {
      padding-bottom: 150%;
      content: '';
      display: block;
    }
  }

  i {
    margin: 2px;
    flex: 1 0 250px;
    height: 0;
  }
}

3. 元素仅宽相同 & 高度自适应 & 列数固定

纵向布局,每列的宽度相同,元素的高度由图片的宽高比例决定,容器总宽度和列数固定。常用于移动端固定两列瀑布流。

参考网站:淘宝手机版

waterfall-taobao.png

优点:

  • 图片不变形
  • 保证完全展示图片内容
  • 错落有致

缺点:

  • 不能按照原始顺序输出,为竖向顺序
  • 非响应式

实现方式:

  1. 使用 多列布局 实现,设置固定的列数
  2. 使用 break-inside: avoid 防止换列时截断
  3. 元素高度使用图片比例自动撑开即可
.container {
  width: 1000px;
  margin: 0 auto;
  column-count: 4;
  column-gap: 4px;
  overflow: hidden;
  border: 1px solid darkgray;

  div {
    break-inside: avoid; // 底部参差不齐而不是换到下一列去
    margin-bottom: 4px;

    img {
      width: 100%;
    }
  }
}

4. 元素仅宽相同 & 高度自适应 & 列数自适应

上一种布局的增强版,使得列数不再固定。因此可以适应各种大小屏幕。容器放大缩小的时候图片大小也会跟随变化,图片有最小的显示宽度,如果当前列数下,图片一行展示不下,则自动减少列数

参考网站:花瓣

waterfall-flower.png

优点:

  • 图片不变形
  • 错落有致

缺点:

  • 不能保证完全展示图片内容
  • 不能按照原始顺序输出,为竖向顺序

实现方式:在上一种方式的基础上添加媒体查询即可

.container {
  width: 100%;
  margin: 0 auto;
  column-count: 2;
  column-gap: 4px;
  overflow: hidden;
  border: 1px solid darkgray;

  div {
    break-inside: avoid;
    margin-bottom: 4px;

    img {
      width: 100%;
    }
  }
}

@media (min-width: 768px) {
  .container {
    column-count: 3;
  }
}

@media (min-width: 992px) {
  .container {
    column-count: 4;
  }
}

@media (min-width: 1200px) {
  .container {
    column-count: 5;
  }
}

5. 元素仅高相同 & 宽度自适应

横线版本的瀑布流,每一行的高度都是相同的,图片元素宽度由图片本身的比例决定。但由于每行的右侧需要对齐占满,但每行图片的宽度之和并不相等,因此图片是无法展示完全的。

参考网站:百度图片

waterfall-bd.png

优点:

  • 图片不变形
  • 错落有致
  • 可按照原始顺序输出

缺点:

  • 不能保证完全展示图片内容

实现方式

  1. 由于不能保证完全展示图片内容,为避免图片拉伸,使用 object-fit: cover 裁切图片
  2. 给每张图片设定 固定高度 和 100% 的宽度 之后使用 flex 布局即可
  3. 解决最后一行展示问题
.container {
  width: 100%;
  border: 1px solid darkgray;
  display: flex;
  flex-wrap: wrap;

  &:after {
    content: '';
    display: block;
    flex-grow: 99999;
  }

  div {
    margin-right: 4px;
    margin-bottom: 4px;
    flex-grow: 1;

    img {
      object-fit: cover;
      height: 300px;
      width: 100%;
    }
  }
}

6. 每行元素高相同 & 行高自适应 & 宽度自适应

各个行的行高不同,图片的宽度也不同,分别自适应以将图片展示完全。

参考网站:500px

waterfall-500-1.png

优点:

  • 图片不变形
  • 错落有致
  • 可按照原始顺序输出
  • 可显示图片完整内容

实现方式:

  1. 首先参考 demo 通过修改 padding 的百分比我们可以实现一个等比例的容器。
  2. 我们可以事先从后台获取到图片的宽高,因此我们就可以针对每一张图片设置和其等比例的容器。demo 。实现的方式就是我们先设定每行的高度为 200px ,因此每个图片容器的宽度就等于 200px * 图片宽/图片高,最后设置 padding-bottom 的比例为元素的高宽比以撑开父元素,使其维持宽高比。
  3. 然后让图片的宽度为 100% 以占满整个容器 demo
  4. 然后考虑如何让每行的元素占满整个页面,通过 flex grow 我们可以实现这一点,但是每个元素的放大比例是多少呢。

    在前面不 grow 的情况下,每张图片的容器的宽度已经是按比例分配了,而想要实现前一行描述的分配方式,每行的剩余空间,我们希望它仍然按照目前容器宽度所占的比例来分配。因此值显然不是均为1,如果均为1那么每张图片的放大比例均相同,导致的结果就是宽的图片和窄的图片获得的放大量是一样的,比如之前一个100px 和 300px 的图片,均放大 100px 就变为了 200 和 400,由1:3的比例变味了1:2的比例了。由例子我们可以看出,放大比例值其实就是每个容器当前的宽度,即放大前两张图宽度比为1:3,放大后我们希望的放大比例也为1:3。因此将 flex-grow 的值设置为容器宽度就可以了。

    demo

  5. 最后处理最后一行的问题
<div class="container-6">
  <div v-for="(item,i) in list" :key="i"
       :style="{flexGrow: item.width / item.height,flexBasis: item.width / item.height * 200 + 'px'}">
    <img :src="item.url" alt=""/>
    <i :style="{paddingBottom:item.height / item.width * 100 + '%'}"></i>
  </div>
</div>
.container {
  width: 100%;
  margin: 0 auto;
  border: 1px solid darkgray;
  display: flex;
  flex-wrap: wrap;

  &:after {
    content: '';
    flex-grow: 999999999;
  }

  div {
    flex: 1 0 200px;
    position: relative;
    overflow: hidden;
    background: red;
    margin: 2px;

    &:after {
      content: '';
      display: block;
      flex-grow: 99999;
    }

    i {
      display: block;
    }

    img {
      position: absolute;
      top: 0;
      width: 100%;
    }
  }
}

demo 样例 参考文章

文章导航