首页 > 建站教程 > Div+Css >  纯CSS的瀑布流布局方法总结正文

纯CSS的瀑布流布局方法总结

瀑布流布局出来好多年了,刚出来时,一般都采用js来实现,涌现了很多比较好的js插件,例如:masonry.js、gridify.js等等。这里就不再详说如何使用了,网上都能找到。今天讨论的是纯CSS实现瀑布流布局。

一、多个列表并列的瀑布流布局法:
    这种布局方法非常简单,就是将多个列表横向排列,每个列表拥有的项都差不多。图片宽度固定,高度自动撑起来。
    html:
<div class="wrap">
 <ul class="waterfall">
 <li class="item"><img src="image/1.jpg"></li>
 <li class="item"><img src="image/3.jpg"></li>
 <li class="item"><img src="image/5.jpg"></li>
 <li class="item"><img src="image/7.jpg"></li>
 <li class="item"><img src="image/9.jpg"></li>
 </ul>
 <ul class="waterfall">
 <li class="item"><img src="image/2.jpg"></li>
 <li class="item"><img src="image/4.jpg"></li>
 <li class="item"><img src="image/6.jpg"></li>
 <li class="item"><img src="image/8.jpg"></li>
 <li class="item"><img src="image/10.jpg"></li>
 </ul>
</div>
    css:
.wrap{
 display:flex;
 justify-content: space-between;
}
.waterfall{
 width:50%;
}
.waterfall .item img{
 width:100%;
}
    注:
    1、waterfall也可以浮动,wrap清除浮动,只要两个列表在一行就行。
    2、每一块 item 都是从上往下排列的,并不能实现从左往右,解决办法是:在获取数据时,需要将数据按奇偶进行分类显示(假设显示两列,多列同理)。您可以定义两个数组:listEven和listOdd,分别来接受获取的数据的偶数项和奇数项,然后分别进行渲染。这里用VUE来演示:
//假设res.data为ajax请求到的数据
res.data.map(function(item,index){
 index%2===0 ? that.listEven.push(item) : that.listOdd.push(item);
})
<div class="wrap">
 <ul class="waterfall">
 <li class="item" v-for="(item,index) in listEven" :key="'even'+index"><img :src="item"></li>
 </ul>
 <ul class="waterfall">
 <li class="item" v-for="(item,index) in listOdd" :key="'odd'+index"><img :src="item"></li>
 </ul>
</div>
    3、这种布局方法,会有一个问题,如果item高度左右列相差很大,就会显示有问题,如下图,解决办法给item一个max-height,超过图片这个max-height就隐藏,此外,后台在传图片时做裁切更好:


二、CSS3 column瀑布流布局法:
    CSS3 column多列可以非常轻松的实现瀑布流效果,它会自动将列表项分配到根据设置的列数当中去,先看下它的常用属性:
        column-count:列数 给waterfall加
        column-width:列的宽度
        column-gap:列之间的间隙
        break-inside:avoid 禁止列表项断裂,即左边列表项的内容有可能跑到右边的最上面 给item加
        点击查阅:column css3 详解

    html
<ul class="waterfall">
 <li class="item"><img src="1.jpg"></li>
 <li class="item"><img src="2.jpg"></li>
 <li class="item"><img src="3.jpg"></li>
 <li class="item"><img src="4.jpg"></li>
 <li class="item"><img src="5.jpg"></li>
 <li class="item"><img src="6.jpg"></li>
 <li class="item"><img src="7.jpg"></li>
 <li class="item"><img src="8.jpg"></li>
 <li class="item"><img src="9.jpg"></li>
 <li class="item"><img src="10.jpg"></li>
</ul>
    css
.waterfall{
 column-count:2;
}
.waterfall .item{
 break-inside: avoid;
}
    效果如下:


    注:
        1、每一块 item 都是从上往下排列的,并不能实现从左往右,第一种方法采用了奇偶两个数组解决了,这个不好解决,如果带有上拉加载,不确定总个数,就更不好解决了。
        2、item的上下间距尽量不要用margin,否则可能会出现下面这种情况,这是因为左列最后一个margin跑到右边上面去了,改成padding即可,因为padding属于item的内容,而break-inside: avoid则禁止item折断,详见 css3 column多列瀑布流布局顶部不对齐


三、CSS3 flex竖排瀑布流布局法
    CSS3的flex用法很多。大多数情况都是用来横排,将块状容器显示在一行,还有就是用来对其一行。但是,改变flex-direction就可以做到纵向排列。

    html
<ul class="waterfall">
 <li class="item"><img src="1.jpg"></li>
 <li class="item"><img src="2.jpg"></li>
 <li class="item"><img src="3.jpg"></li>
 <li class="item"><img src="4.jpg"></li>
 <li class="item"><img src="5.jpg"></li>
 <li class="item"><img src="6.jpg"></li>
 <li class="item"><img src="7.jpg"></li>
 <li class="item"><img src="8.jpg"></li>
 <li class="item"><img src="9.jpg"></li>
 <li class="item"><img src="10.jpg"></li>
</ul>
    css
.waterfall{
 /*flex-box*/
 display: flex;
 /*纵向排列*/
 flex-direction: column;
 /*换列*/
 flex-wrap: wrap;
 height: 100vh;
}
.waterfall .item{
 width:50%;
}
    注:
        1、flex-wrap: wrap 是为了让item撑满waterfall的时候换列(可以理解为换行)
        2、这里waterfall的height一定要写,否则,waterfall随着内容变多,不断撑高也不会换列。
        3、waterfall的height要随着item的数量变化而变化,否则,一列显示不了就显示两列,两列显示不了就显示三列,为了维持固定的列数,只能不断升高waterfall的高度。
        4、flex-direction: column和flex-wrap: wrap可以合并为flex-flow: column wrap;
        5、与前面两种方法一样,这种方法仍然是不好解决从上往下排列而非从左往右排列的问题。

    总结:纯CSS实现瀑布流,总有这样或那样的问题,最终还是要通过js来控制。如果对排序没有要求的话,第二种方法还是比较好用的。纯css实现瀑布流,大家还有什么好的方法,欢迎留言评论。关注IT学堂,会有更多惊喜哦!

    下面摘录的是js 瀑布流实现的详细代码:

        css 的绝对定位方式:根据每张图片的位置设置 top 和 left 值:
//瀑布流效果
//这里有一个坑(已经修复):
//因为是动态加载远程图片,在未加载完全无法获取图片宽高
//未加载完全就无法设定每一个item(包裹图片)的top。
//item的top值:第一行:top为0
//            其他行:必须算出图片宽度在item宽度的缩小比例,与获取的图片高度相乘,从而获得item的高度
//                   就可以设置每张图片在瀑布流中每块item的top值(每一行中最小的item高度,数组查找)
//item的left值:第一行:按照每块item的宽度值*块数
//             其他行:与自身上面一块的left值相等
function waterFall() {
    // 1- 确定图片的宽度 - 滚动条宽度
    var pageWidth = getClient().width-8;
    var columns = 3; //3列
    var itemWidth = parseInt(pageWidth/columns); //得到item的宽度
    $(".item").width(itemWidth); //设置到item的宽度
    
    var arr = [];

    $(".masonry .item").each(function(i){
        var height = $(this).find("img").height();
        var width = $(this).find("img").width();
        var bi = itemWidth/width; //获取缩小的比值
        var boxheight = parseInt(height*bi); //图片的高度*比值 = item的高度

        if (i < columns) {
            // 2- 确定第一行
            $(this).css({
                top:0,
                left:(itemWidth) * i
            });
            arr.push(boxheight);
        } else {
            // 其他行
            // 3- 找到数组中最小高度  和 它的索引
            var minHeight = arr[0];
            var index = 0;
            for (var j = 0; j < arr.length; j++) {
                if (minHeight > arr[j]) {
                    minHeight = arr[j];
                    index = j;
                }
            }
            // 4- 设置下一行的第一个盒子位置
            // top值就是最小列的高度 
            $(this).css({
                top:arr[index],
                left:$(".masonry .item").eq(index).css("left")
            });
            // 5- 修改最小列的高度 
            // 最小列的高度 = 当前自己的高度 + 拼接过来的高度
            arr[index] = arr[index] + boxheight;
        }
    });
}

//clientWidth 处理兼容性
function getClient() {
    return {
        width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
        height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
    }
}

 // 页面尺寸改变时实时触发
window.onresize = function() {
    //重新定义瀑布流
    waterFall();
};

//初始化
window.onload = function(){
    //实现瀑布流
    waterFall();
}