瀑布流式布局小记

下面文章来自公司同事分享

一、场景

实际预期

二、概念

“瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。最早采用此布局的网站是 Pinterest ,逐渐在国内流行开来。国内大多数清新站基本为这类风格。” -- 《百度百科》

三、特点

  1. 高度不等宽度相等:每个内容块高度可以不等,但宽度相等
  2. 排列规律:从左到右再从上到下排列
  3. 列数固定:根据不同的屏幕尺寸固定列数
  4. 空间利用率高:有效利用页面空间
  5. 视觉冲击:不对称的分布具有一定的层次感,给用户带来新颖且有趣的视觉体验
  6. 沉浸式浏览:从上至下连续查看内容,沉浸式阅读,有助于延长用户在页面上的停留时间

四、方案

4.1、分栏布局

.container {
    column-count: 2;
    column-gap: 10px;
    counter-reset: count;
    width: calc(100vw - 24px);
    margin: 0 auto;
    padding: 0;
}
.flowRecord {
    position: relative;
    margin-bottom: 10px;

    &::after {
        counter-increment: count;
        content: counter(count);
        width: 2em;
        height: 2em;
        background-color: rgba(0, 0, 0, 0.9);
        color: #ffffff;
        line-height: 2em;
        text-align: center;
        position: absolute;
        font-size: 1em;
        z-index: 2;
        left: 0;
        top: 0;
    }
}

代码简单,无代码逻辑 可以无限加载 排列规律,先上下再左右,但不满足第二条

4.2、弹性布局

.container {
    display: flex;
    flex-wrap: wrap;
    flex-direction: column;
    height: 1300px;
    margin: 0;
    padding: 0;
}
.flowRecord {
    position: relative;
    width: calc((100vw - 24px) / 2);
    padding: 8px;
    box-sizing: border-box;

    &:nth-child(2n+1) {
        order: 1;
    }

    &:nth-child(2n) {
        order: 2;
    }
}

代码简单,无代码逻辑 可以无限加载 排列无规律,难以控制 区块过少时布局不可控

4.3、网格布局

.container {
    display: grid;
    grid-gap: 10px; // 设置行列间距
    grid-auto-rows: 30px; // 这里设定默认行高
    width: 100%;
        grid-template-columns: repeat(2, 1fr); // 设置列数
}
// 设置行高
.flowRecord[data-row='1'] {
    grid-row: auto / span 1;
}
.flowRecord[data-row='2'] {
    grid-row: auto / span 2;
}
.flowRecord[data-row='2.5'] {
    grid-row: auto / span 2.5;
}
.flowRecord[data-row='3'] {
    grid-row: auto / span 3;
}

实现简单,无代码逻辑 需固定行高,实际业务中很难固定

4.4、js+定位

// 获取元素最小高度
const minColumn = (columnHeight) => {
    let minIndex = -1,
        minHeight = Infinity;

    for(let i = 0; i < columnHeight.length; i ++) {
        if (columnHeight[i] < minHeight) {
            minHeight = columnHeight[i];
            minIndex = i;
        }
    }

    return {
        minIndex,
        minHeight,
    };
};
// 获取元素的定位位置
const computedCardPos = useMemo(() => {
    const cardPos = [];
    const columnHeight = [];
    const recordWidth = cardWidth / 2;

    dataSource.forEach((item, index) => {
        const cardHeight = item.height + 40 + 28;

        // 前两个元素top固定为0
        if (index < 2) {
            cardPos.push({
                left: index % 2 === 0 ? 0 : index * recordWidth,
                top: 0,
            });
            columnHeight[index] = cardHeight;
        } else {
            const { minIndex, minHeight } = minColumn(columnHeight);
            cardPos.push({
                left: minIndex % 2 === 0 ? 0 : minIndex * recordWidth,
                top: minHeight,
            });
            columnHeight[minIndex] += cardHeight; // 高度累加
        }
    });
    return cardPos;
}, [cardWidth, dataSource]);

控制灵活,随意扩展 可以无限加载,不用过多考虑兼容问题 排列规律,从左到右再从上到下 可以添加诸多动画来增强用户体验

4.5、多列布局

根据展示的单行列数,分多个数据渲染

五、业内插件

六、知识点