The waterfall flow

Waterfall flow, also known as waterfall flow layout. A popular web page layout that visually presents a jagged, multi-column layout that loads blocks of data and appends them to the current end as the page scrollbars scroll down. Pinterest was one of the first sites to use this layout, and it became popular in China. Most of the fresh stations in China are basically in this style.(This article mainly introduces the JS implementation part, the HTML part is very brief, the code will be posted together at the end of the article)

The characteristics of

1. Waterfall stream is very attractive to users. It constantly loads new hints at the bottom of the page and gives you incomplete visual images to attract your curiosity and keep you wanting to explore further down.

2. Waterfall stream has more concentrated information and can obtain the most content experience with the minimum operation cost. Therefore, Waterfall stream can better adapt to mobile terminals. A waterfall layout allows users to scroll through content.

3. In addition, the main characteristics of waterfall flow are: fixed width and variable height. This page design is different from the traditional matrix picture layout mode, and cleverly uses visual hierarchy and arbitrary flow of sight to relieve visual fatigue.

Realize the principle of

Waterfall flow has two main characteristics

1. The width of the content box is fixed, but the height is not. 2. The content boxes are arranged from left to right. When one row is full, the remaining content boxes are arranged in order after the short column.

(The least binary tree can be used to simulate the waterfall flow formation algorithm)

First we calculate how many columns a row can hold (because we need to browse on different devices)

Then find the column with the smallest sum of heights of the elements in this column by calculating and comparing

(Let’s say it’s this column that we’ve framed.)

Then add the first element in the next row below the column with the smallest sum of heights

It then continues to calculate the column with the smallest sum of heights, and continues to add new elements after the column with the smallest sum of heights until all elements are added.

Implementation steps and algorithms

1. Import the image and set it to Position: relative

    #container{
        position: relative;
    }
Copy the code

2. Create a JS file and import it in an HTML file

	<script src="./index.js"></script>
Copy the code

3. Monitor the loading status of each picture globally for the placement of subsequent pictures

window.onload = function () {
    imgLocation('container'.'box')}Copy the code

4. Get the number of images you want on the page

function imgLocation(parent, content) {
	var cparent = document.getElementById(parent)
	var ccontent = getChildElemnt(cparent, content)
}

function getChildElemnt(parent, content) {
    const contentArr = []
    const allContent = parent.getElementsByTagName(The '*')
	// Get all the child containers in 'parent'
    for (var i = 0; i < allContent.length; i++) {
        if (allContent[i].className == content) {
            contentArr.push(allContent[i])
        }
    }
    // Get the desired number of child containers
    return contentArr
}
	// You can also use dom's querySelectorAll() method here
Copy the code

5. Find the width of the image and the position where the image needs to be inserted

	var imgWidth = ccontent[0].offsetWidth
	// Get the width of the image
	var num = Math.floor(document.documentElement.clientWidth / imgWidth)
	// Get the number of images that can be placed in a row
	cparent.style.cssText = `width: ${imgWidth * num} px`
	 
Copy the code

6. Place the image that needs to be placed in the exact position, and cycle through, adding all the images on the page according to the desired position

    var BoxHeightArr = []
    for (var i = 0; i < ccontent.length; i++) {
        if (i < num) {
            BoxHeightArr[i] = ccontent[i].offsetHeight
        } else {
            var minHeight = Math.min.apply(null, BoxHeightArr)
            var minIndex = getMinHeightLocation(BoxHeightArr, minHeight)
            ccontent[i].style.position = 'absolute'
            ccontent[i].style.top = minHeight + 'px'
            ccontent[i].style.left = ccontent[minIndex].offsetLeft + 'px'
            BoxHeightArr[minIndex] = BoxHeightArr[minIndex] + ccontent[i].offsetHeight
        }
    }
    function getMinHeightLocation(BoxHeightArr, minHeight) {
    for (var i in BoxHeightArr) {
        if (BoxHeightArr[i] === minHeight) {
            return i
        }
    }
}

Copy the code

Code share

HTML

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta < span style> *{margin: 0; max-width: 100%; padding: 0; } #container{ position: relative; } .box{ float: left; padding: 5px; } .box-img{ width: 150px; padding: 5px; border: 1px solid #ccc; box-shadow: 0 0 5px #ccc; border-radius: 5px; } .box-img img{ width: 100%; height: auto; } </style> </head> <body> <div id="container"> <div class="box"> <div class="box-img"> <img src="./img/1.jpg" alt=""> </div> </div> <div class="box"> <div class="box-img"> <img src="./img/2.jpg" alt=""> </div> </div> <div class="box"> <div class="box-img"> <img src="./img/3.jpg" alt=""> </div> </div> <div class="box"> <div class="box-img"> <img src="./img/4.jpg" alt=""> </div> </div> <div class="box"> <div class="box-img"> <img src="./img/5.jpg" alt=""> </div> </div> </div> <script src="./index.js"></script> </body> </html>Copy the code

JS

window.onload = function () {
    imgLocation('container'.'box')}// Get the current number of images to display
function imgLocation(parent, content) {
    // Remove all contents under parent
    var cparent = document.getElementById(parent)
    var ccontent = getChildElemnt(cparent, content)
    var imgWidth = ccontent[0].offsetWidth
    var num = Math.floor(document.documentElement.clientWidth / imgWidth)
    cparent.style.cssText = `width: ${imgWidth * num} px`

    var BoxHeightArr = []
    for (var i = 0; i < ccontent.length; i++) {
        if (i < num) {
            BoxHeightArr[i] = ccontent[i].offsetHeight
        } else {
            var minHeight = Math.min.apply(null, BoxHeightArr)
            var minIndex = getMinHeightLocation(BoxHeightArr, minHeight)
            ccontent[i].style.position = 'absolute'
            ccontent[i].style.top = minHeight + 'px'
            ccontent[i].style.left = ccontent[minIndex].offsetLeft + 'px'
            BoxHeightArr[minIndex] = BoxHeightArr[minIndex] + ccontent[i].offsetHeight
        }
    }
    // console.log(BoxHeightArr);
}


function getChildElemnt(parent, content) {
    const contentArr = []
    const allContent = parent.getElementsByTagName(The '*')
    // console.log(allContent);
    for (var i = 0; i < allContent.length; i++) {
        if (allContent[i].className == content) {
            contentArr.push(allContent[i])
        }
    }
    // console.log(contentArr);
    return contentArr
}

function getMinHeightLocation(BoxHeightArr, minHeight) {
    for (var i in BoxHeightArr) {
        if (BoxHeightArr[i] === minHeight) {
            return i
        }
    }
}

Copy the code