js和三种纯CSS瀑布流布局

1,397 阅读6分钟

1.js

实现思路:

设定每一列盒子的宽度

获取当前窗口的总宽度,从而根据盒子宽度去分成几列

获取所有盒子的元素,定义一个空数组来保存高度

遍历所有容器,开始判断 当页面加载完成,或页面宽度发生变化时,调用函数。

如果当前处于第一行时: 保存当前元素高度。

如果当前不处于第一行时:进行高度对比,通过遍历循环,拿到最小高度和相对应的索引,设置盒子位置并修改当前索引的高度为当前元素高度。

当页面加载完成,或页面宽度发生变化时,调用函数


具体js代码如下,CSS中父元素要设置position的相对定位,子元素float定位

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="home">
    <div class="item">
        <div style="height: 200px">JS</div>
    </div>
    <div class="item">
        <div style="height: 100px">2</div>
    </div>
    <div class="item">
        <div style="height: 150px">3</div>
    </div>
    <div class="item">
        <div style="height: 300px">4</div>
    </div>
    <div class="item">
        <div style="height: 120px">5</div>
    </div>
    <div class="item">
        <div style="height: 250px">6</div>
    </div>
    <div class="item">
        <div style="height: 140px">7</div>
    </div>
    <div class="item">
        <div style="height: 190px">8</div>
    </div>
    <div class="item">
        <div style="height: 240px">9</div>
    </div>
    <div class="item">
        <div style="height: 330px">10</div>
    </div>
    <div class="item">
        <div style="height: 110px">11</div>
    </div>
    <div class="item">
        <div style="height: 145px">12</div>
    </div>
    <div class="item">
        <div style="height: 190px">13</div>
    </div>
    <div class="item">
        <div style="height: 245px">14</div>
    </div>
</div>
</body>
<style>
    #home{
        position: relative;
    }
    .item{
        float: left;
        box-sizing: border-box;
        border: 1px solid red;
        text-align: center;
        width: 310px;
    }
</style>
<script>
    function fall() {
        const itemWidth = 310;//每一项的宽度
        const scrollBarWidth = getScrollbarWidth();//获取滚动条宽度
        const pageWidth = window.innerWidth - scrollBarWidth;//当前页面宽度
        const column = Math.floor(pageWidth / itemWidth );//实际列数,返回小于这个值的最大整数
        console.log(column)
        const items = document.querySelectorAll('.item')//获取所有子元素
        const heightArr = [];//保存最低高度的空数组
        //获取滚动条的宽度
        function getScrollbarWidth() {
            const oDiv = document.createElement('div')//创建一个div
            oDiv.style.cssText = 'width:50px;height:50px;overflowY:scroll'//给div随意设置样式,有滚动条就行
            document.body.appendChild(oDiv);//把div添加到body中
            const  scollbarWidth = oDiv.offsetWidth - oDiv.clientWidth;//最大宽度减可视宽度,获取滚动条
            oDiv.remove();//移除创建的div
            return scollbarWidth;//返回滚动条宽度
        }
        //便利所有项目元素
        for(let i = 0; i < items.length; i++){
            //元素高度
            const height = items[i].offsetHeight;
            //如果处在第一行,如一共3列,i<3
            if (i < column){
                //直接设置元素距离上部的位置和距离左边的距离
                // items[i].style.cssText = 'top:' + gap +  'px;';
                // left:${(itemWidth + gap)*i}px';
                //保存当前元素的高度
                heightArr.push(height)
            }else{
                //不是第一行就进行比对
                let minHeight = heightArr[0];//先保存第一项高度
                let minIndex = 0;//保存第一项索引
                for (let j = 0;j < heightArr.length;j++){
                    //通过循环遍历,拿到高度最小值和最小值的索引
                    if(minHeight > heightArr[j]){
                        minHeight = heightArr[j];
                        minIndex = j;
                    }
                }
                //最小值为当前元素设置top,通过索引设置left
                items[i].style.cssText = 'position: absolute;' + 'top:' + minHeight + 'px;left:'+ (itemWidth)*minIndex + 'px;';
                //修改当前索引高度为当前元素高度
                heightArr[minIndex] = minHeight + height;
            }
        }
    }
    //页面加载完成调用一次
    window.onload = fall;
    //页面尺寸改变再次调用
    window.onresize = fall;
</script>
</html>

5.png

实现了横向排列,并且可以随着页面的变化而动态变更列数,方便添加更改数据,且没有兼容性问题。

缺点;代码繁琐,性能消耗大

2.flex布局

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div class="home">
        <div style="height: 100px">flex</div>
        <div style="height: 200px">2</div>
        <div style="height: 350px">3</div>
        <div style="height: 100px">4</div>
        <div style="height: 100px">5</div>
        <div style="height: 300px">6</div>
        <div style="height: 200px">7</div>
        <div style="height: 150px">8</div>
    </div>
</body>
<style>
    .home{
        display: flex;
        flex-direction: column;
        flex-wrap: wrap;
        width: 100%;
        height: 500px;
    }
    .home div{
         width: 25%;
         border: 1px solid red;
         text-align: center;
         box-sizing: border-box;
     }
</style>
</html>

1.1.png

flex布局中使用column纵向排列,给定容器具体高度后设置warp属性就会自动换列。

缺点:只能纵向开始排列,并且不给定父容器高度它将会一直向下排列不会换列,不方便增添更改数据

3.多栏布局

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div class="home">
        <div style="height: 200px">多栏</div>
        <div style="height: 300px">2</div>
        <div style="height: 150px">3</div>
        <div style="height: 300px">4</div>
        <div style="height: 300px">5</div>
        <div style="height: 200px">6</div>
        <div style="height: 100px">7</div>
        <div style="height: 350px">8</div>
    </div>
</body>
<style>
    .home{
        column-count: 4;
        column-gap: 0;
    }
    .home div{
        text-align: center;
        box-sizing: border-box;
        border: 1px solid red;
        break-inside:avoid /*控制文本块分解成单独的列,以免项目列表的内容跨列*/
    }
</style>
</html>

2.1.png

多栏布局,给定列数即可,子元素一定要给break-inside:avoid属性,不然可能发生盒子一半在第一列,一半在第二列。

缺点:会出现顺序错乱问题,有时横向,有时纵向

IE9及更早 IE 版本浏览器不支持 column-count 属性

4.grid布局

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div class="home">
    <div >grid</div>
    <div >2</div>
    <div >3</div>
    <div >4</div>
    <div >5</div>
    <div >6</div>
    <div >7</div>
</div>
</body>
<style>
    .home div{
        width: 100%;
        border: 1px solid red;
        text-align: center;
        box-sizing: border-box;
    }
    .home{
        display: grid;
        grid-gap: 10px;
        grid-template-columns: repeat(3,1fr);
        grid-auto-rows: 10px;/*每一格的高度*/
    }
    .home div:nth-of-type(3n+1) {
        grid-row: auto / span 5;
    }
    .home div:nth-of-type(3n+2) {
        grid-row: auto / span 6;
    }
    .home div:nth-of-type(3n+3) {
        grid-row: auto / span 8;
    }
</style>
</html>

3.1.png

网格布局(Grid)是最强大的 CSS 布局方式, 它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局,可近似的看成是二维布局。

与上述两种纯CSS方法不同的是它实现了瀑布流的横向排列

缺点:虽然实现了横向排列,每个盒子高度需要手动设置占了几列不能自适应

属于面向未来的CSS布局,兼容性差,暂不支持IE