Method 1: CSS

To use CSS, you just need to add these two lines of code to the container box to implement waterfall flow without going into too much detail

. Content-box {// Number of columns: 5; // Column-gap: 10px; }Copy the code

Method 2: Use JS

Analyze the code logic:

  1. First set im’s box to absolute positioning and its parent to relative positioning.

HTML part structure:

<div class="content-box"> <div class="img-box"><img src="https://c-ssl.duitang.com/uploads/item/202009/15/20200915235152_FsBXU.thumb.1000_0.jpeg" class="img"> </div> <div class="img-box"><img src="https://c-ssl.duitang.com/uploads/item/202004/01/20200401164316_i5rh2.thumb.1000_0.jpeg" class="img"> </div> <-- ...... --> </div>Copy the code

The CSS code:

.content-box {
            width: 1200px;
            position: relative;
            margin: 50px auto;
            border: 1px solid rgba(253, 114, 109, 0.5);
            box-sizing: border-box;
        }
        
        .img-box .img {
            width: 100%;
            height: 100%;
        }
        
        .img-box {
            position: absolute;
            box-sizing: border-box;
        }
Copy the code

2. Calculate the width required for each column:

Obviously, the width of each row = (container width – gap value (number of columns -1))/ number of columns *

  1. When rendering the first of the next row, find the one on the previous row that has the smallest distance from the bottom of the box to the top of the container. Then insert the image, update the height of the existing column, and repeat this step

4. Since you are using network images rather than local images, wait until the image is loaded (or preloaded) before performing the waterfall flow layout, otherwise you will not get the true height of the image

Code implementation:

(function() { var Waterfall = function(opt) { this.el = document.getElementsByClassName(opt.el)[0] this.columns = Opt. The columns this. Gap = opt. Gap / / this. Each box items = this. El. GetElementsByTagName (' div ') / / this. The width of each box imgWith = (this.el.offsetwidth - this.gap * (this.columns - 1)) // Store the current height of each column this.heightarr = [] this.init()} Waterfall.prototype.init = function() { this.render() } Waterfall.prototype.render = function() { var item = null, minIndex = -1 for (var i = 0; i < this.items.length; Item.style.width = this.imgwith + 'px' if (I < this.columns) {item = this.items[I] // set the width of each box. item.style.top = '0px' item.style.left = (this.gap + this.imgWith) * i + 'px' this.heightArr[i] = item.offsetHeight } Else {// Find the minimum height column number minIndex = getMinIndex(this.heightarr) // Add the image item.style.top = this.heightarr [minIndex] + Item.style. left = this.items[minIndex]. OffsetLeft + 'px' // Update the array before the value plus the current image height, Add gap this.heightarr [minIndex] += item.offsetheight + this.gap}} function getMinIndex(arr) {return arr.indexOf(Math.min.apply(null, Arr)} window. The Waterfall = Waterfall}) () / / the last image loaded to start typesetting var imgCount = document. The getElementsByClassName (" img ") imgCount[imgCount.length - 1].onload = function() { new Waterfall({ el: 'content-box', columns: 5, gap: 5 }) }Copy the code
  1. Of course, you can insert them sequentially, just by changing the render() code and removing the height array:
Waterfall.prototype.render = function() { var item = null, index = 0 for (var i = 0; i < this.items.length; Item.style.width = this.imgwith + 'px' if (I < this.columns) {item = this.items[I] // set the width of each box. item.style.top = '0px' item.style.left = (this.gap + this.imgWith) * i + 'px' this.heightArr[i] = item.offsetHeight } Else {// Which column is currently in? Index = index < this.columns? index : Top = this.heightarr [index] + this.gap + 'px' // Left value identical to the box with the same number of columns in the first row item.style.left = This.items [index].offsetLeft + 'px' Add gap this.heightarr [index] += item.offsetheight + this.gap}}Copy the code

Although this can cause problems with the ending image: