Implementing a Waterfall Layout

Waterfall, also known as waterfall-style layout, is a popular website page layout. It visually presents a multi-column layout with irregular heights. As the page scroll bar scrolls down, this layout continuously loads data blocks and appends them to the current end. The main feature of the waterfall layout is its organized and fixed-width but variable-height design, which distinguishes it from the traditional matrix-style image layout pattern.

Example

The main idea is to record the height of each column. The parent container is relatively positioned, and the members are absolutely positioned. The top and left properties are used to control the position. When adding a new member, find the column with the lowest height and place the member below it to achieve the waterfall layout. If dynamic addition of members is not needed and only one-time loading for display is required, you can consider using the flex layout to set the container as flex-direction: column; and flex-wrap: wrap;, and give the container a suitable height to achieve the layout. You can also use the column-* multi-column layout introduced by CSS3 to achieve this. These two methods are pure CSS implementations of the waterfall layout. However, because both methods arrange members vertically, they are not suitable for layouts that require dynamic insertion of members. When dynamic insertion of members is needed, JavaScript is still required for implementation.

<!DOCTYPE html>
<html>
<head>
    <title>JavaScript Waterfall Layout</title>
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1" />
    <style type="text/css">
        #container{
            position: relative; /* Parent container relative */
        }
        .item{
            position: absolute; /* Members set as absolute */
            display: flex; /* Mainly for centering text */
            justify-content: center; /* Horizontal centering */
            align-items: center; /* Vertical centering */
            color: #fff; /* Font color white */
        }
    </style>
</head>
<body>
    <div id="container"></div>
</body>
    <script type="text/javascript">
        var column = 3; // Create a three-column layout
        var counter = 0; // Counter for displaying the current block
        var columnHeight = Array(column).fill(0); // Record the height of each column
        var container = document.getElementById("container"); // Parent container object
        var colorList = ["#EAA78C", "#F9CD82", "#9ADEAD", "#9CB6E9", "#E49D9B", "#97D7D7", "#ABA0CA", "#9F8BEC","#ACA4D5", "#6495ED", "#7BCDA5", "#76B4EF","#E1C38F","#F6C46A","#B19ED1","#F09B98","#87CECB","#D1A495","#89D196","#FE9E9F", "#93BAFF", "#D999F9", "#81C784", "#FFCA62", "#FFA477"]; // Color list
         
        function random(min=0, max=1) { // Generate random numbers
          return min + ~~((max-min)*Math.random()) // min <= random < max 
        }
function findMinColumn(arr) { // Find the column with the minimum height
    var min = arr[0];
    var index = 0;
    arr.forEach((v, i) => {
        if (v < min) {
            min = v;
            index = i;
        }
    })
    return [index, min];
}


function appendImg() {
    var gap = 3; // Set the gap to 3px
    for (let i = 0; i < 12; ++i) { // Load 12 members each time
        var unit = {
            height: random(100, 500), // Randomize an undefined height
            width: 300, // Set width
            color: colorList[random(0, colorList.length)] // Randomize color
        }
        var [minIndex, min] = findMinColumn(columnHeight); // Get the column with the minimum height and its index
        var d = document.createElement("div"); // Create a node
        d.className = "item"; // Set class
        d.style.background = unit.color; // Set background color
        d.style.height = `${unit.height}px`; // Set height
        d.style.width = `${unit.width}px`; // Set width
        d.style.top = `${min + gap}px`; // Set top offset
        d.style.left = `${(300 + gap) * minIndex}px`; // Set left offset
        d.innerText = `${++counter}#${unit.height}X${unit.width}`; // Set text
        columnHeight[minIndex] += (unit.height + gap); // Update the height of the selected column
        container.appendChild(d); // Add node
    }
}

function init() {
    appendImg(); // Initial load
    var endLoad = columnHeight.some(v => v > window.innerHeight); // Check if any column height is greater than the screen height
    if (!endLoad) init(); // If not, recursively call to continue loading
}

(function () {
    init(); // Automatically load when the page opens
})();
window.onscroll = function (){ // Browser scroll to bottom event
    var marginBottom = 0;
    if (document.documentElement.scrollTop){
        var scrollHeight = document.documentElement.scrollHeight;
        var scrollTop = document.documentElement.scrollTop + document.body.scrollTop;
        var clientHeight = document.documentElement.clientHeight;
        marginBottom= scrollHeight - scrollTop - clientHeight;
    } else {
        var scrollHeight = document.body.scrollHeight;
        var scrollTop = document.body.scrollTop;
        var clientHeight = document.body.clientHeight;
        marginBottom= scrollHeight - scrollTop - clientHeight;
    }
    if(marginBottom<=0) appendImg();
}

</script>
</html>

Daily Question

https://github.com/WindrunnerMax/EveryDay

Reference

https://www.cnblogs.com/imgss/p/11072266.html https://blog.csdn.net/weixin_44135121/article/details/98629830