css页面布局--瀑布流布局

首先我们看下,什么叫瀑布流?

瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。

比如下面这个网站,便是瀑布流布局:

image

使用column-count和column-gap来实现瀑布流布局(适合简单的瀑布流排版)

body {
  margin: 4px;
  font-family: Arial, Helvetica, sans-serif;
}

.masonry {
  column-count: 4;
  column-gap: 0;
}

.item {
  padding: 2px;
  position: relative;
  counter-increment: count;
}

.item img {
  display: block;
  width: 100%;
  height: auto;
}

.item::after {
  position: absolute;
  display: block;
  top: 2px;
  left: 2px;
  width: 24px;
  height: 24px;
  text-align: center;
  line-height: 24px;
  background-color: #000;
  color: #fff;
  content: counter(count);
}
<body>
    <div class="masonry">
        <div class="item">
            <img src="https://picsum.photos/360/460?radom=1" alt="">
        </div>
        <div class="item">
            <img src="https://picsum.photos/360/520?radom=2" alt="">
        </div>
        <div class="item">
            <img src="https://picsum.photos/360/420?radom=3" alt="">
        </div>
        <div class="item">
            <img src="https://picsum.photos/360/500?radom=4" alt="">
        </div>
        <div class="item">
            <img src="https://picsum.photos/360/420?radom=5" alt="">
        </div>
        <div class="item">
            <img src="https://picsum.photos/360/460?radom=6" alt="">
        </div>
        <div class="item">
            <img src="https://picsum.photos/360/480?radom=7" alt="">
        </div>
        <div class="item">
            <img src="https://picsum.photos/360/460?radom=8" alt="">
        </div>
        <div class="item">
            <img src="https://picsum.photos/360/420?radom=9" alt="">
        </div>
        <div class="item">
            <img src="https://picsum.photos/360/500?radom=10" alt="">
        </div>
        <div class="item">
            <img src="https://picsum.photos/360/460?radom=11" alt="">
        </div>
        <div class="item">
            <img src="https://picsum.photos/360/360?radom=12" alt="">
        </div>
    </div>
</body>

image

不足之处:

图片顺序是从上到下排列。如果你的网页是要按照时间倒序来展示照片,那么,我们就需要照片先从左至右排列,在换行,所以目前这种方式虽然简单,但是很多场景中不适合使用。

flexBox方式实现瀑布流布局(不推荐)

我们还是使用刚才的html格式,css布局方式改成flex布局。
关于flex布局可以看我另一篇文章:Flex布局
如果我们将flex容器的高度设置为1000px固定高度,且flex-direction设置为colunm方式,那么,当高度无法容纳所有图片时候,在flex-wrap: wrap的情况下,多余的图片变会在主轴方向换行。如下图所示:

body {
  margin: 4px;
  font-family: Arial, Helvetica, sans-serif;
}

.masonry {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  height: 1000px;


}

.item {
  position: relative;
  width: 25%;
  padding: 2px;
  counter-increment: count;
}

.item img {
  display: block;
  width: 100%;
  height: auto;
}

.item::after {
  position: absolute;
  display: block;
  top: 2px;
  left: 2px;
  width: 24px;
  height: 24px;
  text-align: center;
  line-height: 24px;
  background-color: #000;
  color: #fff;
  content: counter(count);
}

image

但是,这里会发现我们展示的图片排序也是自上而下的顺序排序。

但是在flex中,我们可以使用order值来改变图片顺序,从而满足有从左至右排序的要求,代码如下:

/**因为column为主轴,那么我们就规定第1,5,9张照片顺序优先,在主轴,也就是纵列先展示,
2,6,10张照片在第二列展示,以此类推,这里用了数学方式取了个巧**/
.item:nth-child(4n+1) {
  order: 1;
}

.item:nth-child(4n+2) {
  order: 2;
}

.item:nth-child(4n+3) {
  order: 3;
}

.item:nth-child(4n+4) {
  order: 4;
}

image

此时,网页便如图效果。

不足之处:

我们如果缩放浏览器宽度:

image

由于flex的容量的高度是固定的,这时候缩小容器的宽度,而容器内的图片高度又因为宽度而改变(图片宽度设置成width: 100%),这时候flex只需要分成两列,便可以容纳所有图片,而我们只是用了数学方式来取巧规定了顺序,而交叉轴宽度变小,打乱了原先布局,能那么这时候图片顺序又会被打乱。便会如上图效果。

第三方插件实现瀑布流(推荐)

在这里,我是比较推荐使用第三方插件来实现瀑布流布局的。

我这里使用masonry来举例

→→→→→masonry官网←←←←←

按照官网介绍来看下:

Masonry is a JavaScript grid layout library. It works by placing elements in optimal position based on available vertical space, sort of like a mason fitting stones in a wall. You’ve probably seen it in use all over the Internet.

大概意思是Masonry是个第三方布局插件,让你变得像个堆砌砖墙的工匠一样,把空间里的元素放置在最佳的位置。有点难以理解吧,我们直接上代码。

<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>

这里我们用CDN方式引入jquery和masony插件。

下面是我写的css代码

body {
  margin: 0;
  padding: 0;
  font-family: Arial, Helvetica, sans-serif;
}

.grid-item {
  position: relative;
  width: 25%;
  border: 2px solid hsla(0, 0%, 0%, 0.5);
  box-sizing: border-box;
  counter-increment: count;
}


.grid-item img {
  display: block;
  height: auto;
  width: 100%;
}


.grid-item::after {
  position: absolute;
  display: block;
  top: 2px;
  left: 2px;
  width: 24px;
  height: 24px;
  text-align: center;
  line-height: 24px;
  background-color: #000;
  color: #fff;
  content: counter(count);
}
<body>
  <div class="grid">
    <!-- 第一行 -->
    <div class="grid-item">
      <img src="./img/1.jpg" alt="">
    </div>
    <div class="grid-item">
      <img src="./img/2.jpg" alt="">
    </div>
    <div class=" grid-item">
      <img src="./img/3.jpg" alt="">
    </div>
    <div class="grid-item">
      <img src="./img/4.jpg" alt="">
    </div>
    <!-- 第二行 -->
    <div class="grid-item">
      <img src="./img/5.jpg" alt="">
    </div>
    <div class="grid-item">
      <img src="./img/6.jpg" alt="">
    </div>
    <div class="grid-item">
      <img src="./img/7.jpg" alt="">
    </div>
    <div class="grid-item">
      <img src="./img/8.jpg" alt="">
    </div>
    <!-- 第三行 -->
    <div class="grid-item">
      <img src="./img/9.jpg" alt="">
    </div>
    <div class="grid-item">
      <img src="./img/10.jpg" alt="">
    </div>

    <div class="grid-item ">
      <img src="./img/11.jpg" alt="">
    </div>
    <div class="grid-item">
      <img src="./img/12.jpg" alt="">
    </div>
    <div class="grid-item">
      <img src="./img/13.jpg" alt="">
    </div>
    <div class="grid-item">
      <img src="./img/14.jpg" alt="">
    </div>

  </div>
</body>

我把每个照片都宽度设置成了25%。也就是在每行会呈现4张照片。接下来是js代码

var $grid = $('.grid').masonry({
  itemSelector: '.grid-item', 
  percentPosition: true, //使用百分比宽度的响应式布局
  horizontalOrder: true, //对项目进行布局以保持水平的从左到右的顺序,定义了此条件,照片一般会按照从左到右顺序排列,但也不是绝对的。
  originLeft: true, //设置布局方式为从左到右,此项是默认值,可以不填写,如果你设置值为false,则会从右到左排序
  originTop: true,//设置布局方式为从上到下,此项是默认值,可以不填写,如果你设置值为false,则会从下到上排序
  transitionDuration: '0.8s',//更改位置或外观时的过渡持续时间,默认是0.4s
  resize:true, //调整窗口大小时自动调整元素大小和位置,此项不推荐关闭
  initLayout: true,//默认为true,在初始化时候启用布局,如果设置为在初始化时禁用布局,可以在初始布局之前使用方法或添加事件,执行玩自定义方法后,在使用$grid.masonry()方法来初始化
})

//如果我initLayout: false,那么在初始化布局前,会先执行此方法,然后在调用$('.grid').masonry()方法进行初始化,下面方法只是举例
$grid.masonry( 'on', 'layoutComplete', function() {
  console.log('layout is complete');
});
// 如果initLayout: true,则不需要此方法
$grid.masonry();

/** masonry的配置项一共有以下,不再多做介绍,可以自行去看英文官网。
- Recommended 
- itemSelector 
- columnWidth 
- Layout
- Element sizing 
- gutter
- horizontalOrder 
- percentPosition
- stamp 
- fitWidth
- originLeft 
- originTop
- Setup 
- containerStyle 
- transitionDuration 
- stagger 
- resize 
- initLayout
**/

设置完毕后,得到如下图的布局展示,因为我设置了horizontalOrder: true原因,所以图片排版会尽量按照从左到右方式来布局。并且因为我设置的图片宽度为百分比,所以无论是缩小和放大元素,一行都会呈现四张图片。

image.png

另外,我们也可以使用固定像素宽度来设置图片,以防图片变形。我们将图片容器的宽度从25%改为200px

 .grid-item {
   position: relative;
   width: 200px;
   border: 2px solid hsla(0, 0%, 0%, 0.5);
   box-sizing: border-box;
   counter-increment: count;
}

将js代码中的masonry配置项中的 percentPosition: true去除。这时候,我们得到的排版效果如下图,我们可以发现照片宽度被固定在200px,并且尽可能占满一行,无法占满则换行。

image

当我们缩小浏览器的宽度时候,照片会自适应宽度布局。如下图:
image

到这里,我们完美实现了瀑布流布局的展示。不过此插件要注意浏览器的兼容性,我在safari使用变没有生效,而chrome则没有问题。

类似的插件还有isotope等,在这里不再铺开说了,masonry也有着各种各样的布局方式,感兴趣的可以去官网看。

阅读 296

推荐阅读