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