Hello everyone, I’m Brother Echa. I remember that I introduced to you the waterfall flow layout two years ago and implemented it with a pure CSS solution. I wonder if fans still remember it? It doesn’t matter if you don’t remember, please see "Dry Information" Pure CSS to Realize

2024/03/2823:27:32 hotcomm 1338

Hello everyone, I am Brother Echa. I remember that I introduced the waterfall flow layout to you two years ago and implemented it with a pure CSS solution. I wonder if fans still remember it? It doesn’t matter if you don’t remember, please see Hello everyone, I’m Brother Echa. I remember that I introduced to you the waterfall flow layout two years ago and implemented it with a pure CSS solution. I wonder if fans still remember it? It doesn’t matter if you don’t remember, please see

Preface

Waterfall flow layout is a relatively popular page layout method, which is represented by uneven multi-column cards. Compared with the grid layout, it looks more flexible and artistic. There are many ways to implement waterfall flow layout in

, such as multi-column layout, grid layout, flex layout, etc. However, these implementation methods have their own limitations, and the code is also slightly complex.

In fact, there is the most original, simplest, and most compatible implementation method, which is to use to absolutely position . The elements of the waterfall flow layout are cards with equal width and unequal height. You only need to calculate the coordinate position based on the actual width and height of the element.

naturally requires JavaScript to calculate coordinates. This is not a pure CSS solution and may not be so pure for some front-ends. But once you clarify your ideas, it doesn’t take more than a few lines of code. This article gives a recently implemented version.

// Calculate the coordinates of each card export function calcPositions({ columns = 2, gap = 7, elements }) {if (!elements || !elements.length) {return [];}const y = []; / /The bottom vertical coordinate array of the previous row of cards, used to find the filling position of the new card const positions = []; // The coordinate array of each card elements.forEach((item, index) = {if (y.length columns) { // Not one row has been filled yet y.push(item.offsetHeight);positions.push({left: (index % columns) * (item.offsetWidth + gap),top: 0});} else {const min = Math .min(...y); // Minimum ordinate const idx = y.indexOf(min); // Card index with minimum ordinate y.splice(idx, 1, min + gap + item.offsetHeight); / / Replace with the vertical coordinate of the new card positions.push({left: idx * (item.offsetWidth + gap),top: min + gap});}}); // Due to absolute positioning, the container cannot be opened automatically of. Therefore, it is necessary to calculate the actual height, that is, the top of the last card plus its own height return { positions, containerHeight: positions[positions.length - 1].top + elements[elements.length - 1].offsetHeight };}

The above paragraph The function of the code is to calculate the left, top of each card, and the total height of the container. There are comments at key positions, so it shouldn't be difficult to understand.

With these lines of core code, it is easy to encapsulate it into a waterfall flow component. Taking Vue as an example, it can be encapsulated like this:
MasonryLite.vue

templatediv class="masonry-lite" slot/slot/div/templatescriptimport { calcPositions } from './index.js';export default {name: 'MasonryLite',props: { gap: {type: Number,default: 12,},columns: {type: Number,default: 2,},},data() {return {};},mounted() {this.doLayout();}, methods: {doLayout() {const children = [...this.$el.querySelectorAll('.masonry-item')];if (children.length === 0) {return;}const { positions, containerHeight } = calcPositions({elements: children,columns: this.columns,gap: this.gap,});children.forEach((item, index) = {item.style.cssText = `left:${positions[index]. left}px;top:${positions[index].top}px;`;});this.$el.style.height = `${containerHeight}px`;},},};/scriptstyle lang=" scss" scoped.masonry-lite{position: relative;}.masonry-item {position: absolute;}/style

Use components:

MasonryLitediv class="product-card masonry-item" v-v-for="(item, index) in items" :key="index"img :src="item.imageUrl" /header{{ item.title }}/header/div/MasonryLite

However, there is actually a problem with this, which is the execution timing of doLayout. Because this solution is based on absolute positioning, the actual width and height need to be obtained after the element is rendered. If there are lazy-loaded images or other dynamic content in the card, the height will change.In this case, you need to actively call doLayout to recalculate the layout after the DOM is updated.

If you have a better implementation plan, please share it!

code repository: https://github.com/kaysonli/masonry-lite

npm package: masonry-lite

If you find it helpful, please give me a free star.

hotcomm Category Latest News