瀑布流布局

许多网站采用瀑布流布局的形式对 items 进行排版,看上去很有美感。它看上去像是不规则的网格布局。

瀑布流布局的特点如下:

  • 每列元素宽度固定,高度不定。
  • 下面的元素会仅接着上面的元素放置,不会留下缝隙。

简单实现

我们可以使用简单的 CSS 实现瀑布流布局:

:::: tabs ::: tab HTML

<article>
  <section>
    <p>1.Lorem ipsum dolor sit amet, consectetur.</p>
  </section>
  <section>
    <p>
      2.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error aliquid reprehenderit expedita odio beatae est.
    </p>
  </section>
  <section>
    <p>3.Lorem ipsum dolor sit amet, consectetur.</p>
  </section>
  <section>
    <p>4.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nobis quaerat suscipit ad.</p>
  </section>
  <section>
    <p>
      5.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Rem nihil alias amet dolores fuga totam sequi a
      cupiditate ipsa voluptas id facilis nobis.
    </p>
  </section>
  <section>
    <p>
      6.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Rem ut debitis dolorum earum expedita eveniet
      voluptatem quibusdam facere eos numquam commodi ad iusto laboriosam rerum aliquam.
    </p>
  </section>
  <section>
    <p>7.Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
  </section>
  <section>
    <p>
      8.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quaerat architecto quis tenetur fugiat veniam iste
      molestiae fuga labore!
    </p>
  </section>
  <section>
    <p>
      9.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odit accusamus tempore at porro officia rerum est
      impedit ea ipsa tenetur. Labore libero hic error sunt laborum expedita.
    </p>
  </section>
  <section>
    <p>10.Lorem ipsum dolor sit.</p>
  </section>
  <section>
    <p>
      11.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima asperiores eveniet vero velit eligendi aliquid
      in.
    </p>
  </section>
  <section>
    <p>12.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus dolorem maxime minima animi cum.</p>
  </section>
</article>

::: ::: tab CSS

article {
  column-width: 200px;
  column-gap: 15px;
}

section {
  box-sizing: border-box;
  display: inline-block;
  margin-top: 15px;
  padding: 15px;
  width: 100%;
  border: 1px solid black;
}

 
 




 





::: ::: tab 效果 ::: ::::

就如上面的 CSS 所展示的那样,使用 column-widthcolumn-gap 配合 inline-block 元素就可以生成瀑布流布局。

Notice

column-width 控制列宽,容器将容纳尽可能多的列数但不会让任何一个元素宽度小于列宽。

column-gap 控制每列的间隙。

在 FireFox 上,你可以使用 grid 创造瀑布流:

.container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: masonry;
}

grid-template-rows: masonry 是个不错的设想,但截至文章发布之前,该特性并不被除 FireFox 之外的其他浏览器支持

我们再来看看上面代码实现的效果:

可以发现元素的顺序并没有按照从左到右横向排列,而是按照纵向排列的,也就是说第二个元素排在了第一个元素的下面而不是右边。如何解决这个问题呢?

我们需要使用 nth-child 重新排列元素。

使用 nth-child 重新排列元素

假设我们需要渲染一个三列的瀑布流,那么第一列元素的应该是序号为 1,4,7,9...的元素,他们都满足一个条件,就是序号为 3*(行数-1)+1。同理,第二行为 3*(行数-1)+2,第三行为 3*(行数-1)+3

section:nth-child(3n + 1) {
  order: 1;
}
section:nth-child(3n + 2) {
  order: 2;
}
section:nth-child(3n + 3) {
  order: 3;
}

Notice

order 属性用于在 flexgrid 中对元素进行排序。

然后我们将容器设置成 flex 布局,设置为纵向排列并且可换列:

article {
  display: flex;
  flex-flow: column wrap;
  align-content: space-between;
  height: 600px;
  column-gap: 7.5px;
}

 
 




子元素设置一下宽度和间距:

section {
  width: calc(100% / 3);
  margin-bottom: 15px;
  border: 1px solid black;
}

效果如下:

似乎效果不是预想的那样,由于我们设置容器高度为 600px 的原因,当第一行有充足的空间时,第二行和第三行的元素也合并到前一行来占位置了。

我们可以通过伪元素来分割这三列解决这个问题。

article::before,
article::after {
  content: '';
  flex-basis: 100%;
  width: 0;
  order: 2;
}



 

 

我们将伪元素的 order 设置为 2,那么 ::before 会分割第一和第二行,而 ::after 会分割第二和第三行,我们将这两个伪元素高亮出来看一下:

这样我们就用纯 CSS 实现了一个正常顺序的瀑布流了。

我们可以看出这个方法有一些明显的缺点:

  • 容器必须明确设置足够大的高度,如果渲染无限刷新列表的话,该方法会失效。
  • 列数不能动态改变。
  • 两个伪元素分割的策略在三列以上的瀑布流中不适用。

总结

基于以上的讨论,如果我们及想要响应式渲染,还想要正确的显示顺序,那还是自己找个第三方库来实现吧 😂。

参考文章