The waterfall flow

Results show

define

Waterfall flow is a page layout consisting of multiple modules of the same width and height; Can automatically adapt to achieve line by line display effect. The visual representation is a jagged, multi-column layout that loads blocks of data and appends them to the current tail as the page scrollbars scroll down. This type of waterfall flow is often found on image-based websites.

Why use

  • Because of multi-column distribution, it can better adapt to the mobile terminal;
  • Can break the conventional page layout, have a good visual experience;
  • Uneven layout, favorable to adjust the curiosity of the stroke down, to attract users;

implementation

  • Method 1: Waterfall flow is realized through the columns-count in the multi-column layout of CSS3. The simplest way to do this, but this layout is in vertical order, when the need to scroll load, disadvantages appear. Results the preview
  • Method 2: obtain the width and height of parent element and child element through JS, and traversal the subset element to determine the location of the current element; The CSS position can be used for positioning. Details can be seen in the preview
  • Grid-row-end = grid-row-end = grid-row-end = grid-row-end; Specific details can be seen in the effect display

Note: The specific implementation method can be annotated according to the following code

Methods a

html

<div class="root">
  <div class="item">
    <img src="https://picsum.photos/450/325? image=100" alt="">
  </div>
  <div class="item">
    <img src="https://picsum.photos/450/450? image=200" alt="">
  </div>
  <div class="item">
    <img src="https://picsum.photos/450/280? image=300" alt="">
  </div>
  <div class="item">
    <img src="https://picsum.photos/450/540? image=400" alt="">
  </div>
  <div class="item">
    <img src="https://picsum.photos/450/380? image=500" alt="">
  </div>
  <div class="item">
    <img src="https://picsum.photos/450/300? image=600" alt="">
  </div>
  <div class="item">
    <img src="https://picsum.photos/450/400? image=700" alt="">
  </div>
</div>

Copy the code

css

 .root {
  columns-count: 4;
  column-gap: 10px;
}
img {
  width: 100%;
  border-radius:10px;
  margin-bottom:10px;
}
@media only screen and (max-width: 768px) {
  .root {
    columns: 1; }}@media only screen and (max-width: 992px) and (min-width: 768px) {
  .root {
    columns: 3; }}@media only screen and (max-width: 1200px) and (min-width: 992px) {
  .root {
    columns: 4; }}@media only screen and (min-width: 1200px) {
  .root {
    columns: 6; }}Copy the code

Method 2

html

  <div>
    <div id="root">
    </div>
  </div>
Copy the code

css

    #root {
      position: relative;
      opacity: 0;
    }

    .item {
      position: absolute;
    }

    .item>img {
      width: 200px;
      vertical-align: middle;
    }
Copy the code

js

    const imgList = [
    "https://picsum.photos/450/325? image=10"."https://picsum.photos/450/540? image=11"."https://picsum.photos/450/600? image=12"."https://picsum.photos/450/325? image=13"."https://picsum.photos/450/540? image=14"."https://picsum.photos/450/325? image=15"."https://picsum.photos/450/325? image=16"."https://picsum.photos/450/325? image=17"."https://picsum.photos/450/540? image=18"."https://picsum.photos/450/325? image=19"."https://picsum.photos/450/605? image=20"."https://picsum.photos/450/540? image=21"
    ]
    let itemAll = ' ' // All child nodes
    for (let index = 0; index < imgList.length; index++) {
      itemAll = itemAll + `<div class="item">
        <img src=${imgList[index]} alt="">
      </div>`
    }
    // Function buffeting
    const debounce = (fn) = > {
      let timeOut = null;
      return (e) = > {
        clearTimeout(timeOut)
        timeOut = setTimeout(() = > {
          fn()
        }, 500)}}// Set the width of the image to 200px
    const imgWidth = 200
    / / the parent node
    const rootDom = document.getElementById('root')
    // Add child nodes
    rootDom.innerHTML = itemAll
    // Wait until the image is loaded
    window.addEventListener("load".() = > waterFall())
    window.addEventListener("resize", debounce(() = >waterFall()))
    / / function
    const waterFall = () = > {
      console.log(234);
      rootDom.style.opacity=1
      // Dynamically get the width of the parent node
      const rootWidth = rootDom.offsetWidth
      // Get the number of columns that can be aligned
      const columnNum = Math.floor(rootWidth / imgWidth)
      // Get the child node
      const itemDom = document.getElementsByClassName('item')
      // Height array
      let heightArr = []
      // Traversal the child element
      for (let index = 0; index < itemDom.length; index++) {
        // The current element
        const element = itemDom[index]
        const elementHeight = element.offsetHeight
        // check if the first row subscript is less than the number of columns
        if (index < columnNum) {
          heightArr.push(elementHeight)
          element.style.left = index * imgWidth + 'px';
          element.style.top = 0 + 'px';
        } else {
          const minIndex = minBox(heightArr)
          const minValue = heightArr[minIndex]
          element.style.left = minIndex * imgWidth + 'px';
          element.style.top = minValue + 'px'; heightArr[minIndex] += elementHeight; }}}function minBox(box) {
      var j = 0;
      for (i in box) {
        if (box[j] > box[i]) j = i
      }
      return j;
    }
Copy the code

Methods three

htnml

  <div class="box">
    <div id="root">
    </div>
  </div>
Copy the code

css

    .box {
      max-width: 960px;
      margin-right: auto;
      margin-left: auto;
    }

    #root {
      display: grid;
      grid-template-columns: repeat(1.minmax(100px.1fr));
      grid-gap: 10px;
      grid-auto-rows: 0;
      opacity: 0;
    }

    .item {
      border-radius: 10px;
      border: 1px solid # 000;
      overflow: hidden;
    }

    .item>img {
      max-width: 100%;
      vertical-align: middle;
    }

    @media only screen and (max-width: 1023px) and (min-width: 768px) {
      #root {
        grid-template-columns: repeat(2.minmax(100px.1fr)); }}@media only screen and (min-width: 1024px) {
      #root {
        grid-template-columns: repeat(3.minmax(100px.1fr)); }}Copy the code

js

    const imgList = [
    "https://picsum.photos/450/325? image=10"."https://picsum.photos/450/540? image=11"."https://picsum.photos/450/600? image=12"."https://picsum.photos/450/325? image=13"."https://picsum.photos/450/540? image=14"."https://picsum.photos/450/325? image=15"."https://picsum.photos/450/325? image=16"."https://picsum.photos/450/325? image=17"."https://picsum.photos/450/540? image=18"."https://picsum.photos/450/325? image=19"."https://picsum.photos/450/605? image=20"."https://picsum.photos/450/540? image=21"
    ]
    let itemAll = ' ' // All child nodes
    for (let index = 0; index < imgList.length; index++) {
      itemAll = itemAll + `<div class="item">
      <img src=${imgList[index]} alt="">
    </div>`
    }
    / / the parent node
    const rootDom = document.getElementById('root')
    // Add child nodes
    rootDom.innerHTML = itemAll
    / / the main function
    function resizeAllMasonryItems() {
      const rootDom = document.getElementById('root')
      rootDom.style.opacity = 1
      const itemDom = document.getElementsByClassName('item')
      if (itemDom && rootDom) {
        for (var i = 0; i < itemDom.length; i++) {
          const curDom = itemDom[i]
          // The current element
          var rowGap = parseInt(window.getComputedStyle(rootDom).getPropertyValue('grid-row-gap'))
          // Get the value of grid-auto-rows in the CSS
          var rowHeight = parseInt(window.getComputedStyle(rootDom).getPropertyValue('grid-auto-rows'))
          // Get the img of the current node
          var gridImagesAsContent = curDom.querySelector('img');
          RowHeight is 0 if not set
          var rowSpan = Math.ceil((gridImagesAsContent.offsetHeight + rowGap) / (rowHeight + rowGap));
          // Grid-row-end is critical
          curDom.style.gridRowEnd = 'span '+ rowSpan; }}}window.addEventListener("load", resizeAllMasonryItems)
Copy the code

conclusion

Method one is the simplest, but method two is the most commonly used; Compared with method two, method three is simple, but there is upward rounding, resulting in a certain deviation of the value; Or choose according to the business.


Note:

  • Native waterfall stream style tool can be downloaded online. Methods 1 and 2 refer to the downloaded code to learn
  • The above picture source, the generation of pictures super easy to use