>웹 프론트엔드 >CSS 튜토리얼 >JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개

JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개

青灯夜游
青灯夜游앞으로
2021-07-16 19:45:002662검색

이 기사에서는 폭포 흐름 레이아웃을 살펴보고 신뢰할 수 있는 세 가지 JS 솔루션과 N 신뢰할 수 없는 CSS 솔루션을 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개

오늘은 실용주의를 바탕으로 폭포 흐름 레이아웃을 공유하겠습니다. (어제 동생이 어떻게 하는지 물어봐서 한참을 찾았는데 못 찾았어요. 인트라넷에 작성).

데모 주소: http://www.lilnong.top/static/html/waterfall.html

폭포 흐름 레이아웃이 무엇인가요?

예를 들어 Petals.com, Mogujie(아래 사진을 게시했습니다)에서는 이러한 웹사이트에서는 콘텐츠를 표시할 때 폭포 흐름 레이아웃을 사용합니다.

우리는 또한 디자인 초안을 표시하는 페이지를 만들고 싶습니다(고정 너비, 가변 높이). 폭포 흐름은 훌륭한 솔루션입니다.

폭포 흐름 레이아웃의 핵심은 그리드 레이아웃을 기반으로 하며, 각 행에 포함된 항목 목록의 높이는 무작위입니다(높이는 자체 콘텐츠에 따라 동적으로 변경됩니다). 스택 형태로 배열되는데, 가장 중요한 것은 스택 사이에 불필요한 간격이 없다는 것입니다. 위의 그림을 보고 우리가 말하는 폭포 흐름 레이아웃이 어떻게 생겼는지 살펴보겠습니다.

Website Mogujie Petal.com JD VV
스크린샷 JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개 JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개 JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개 JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개
Scheme 하위 채널 absolute

grid, inline, float Magic 솔루션

은 본질적으로 왼쪽에서 오른쪽으로 문서 흐름에 의존합니다. , 위에서 아래로.

계획gridinlinefloatbootstrap-gridscreenshot

문서 흐름 레이아웃에는 line이라는 매우 분명한 개념이 있음을 알 수 있습니다. 줄을 늘리면 공백이 생기고 줄이 겹치지 않습니다. 여기서 가장 놀라운 점은 플로트 레이아웃입니다.

DOM 구조

div.list     // 设置 gird 或者 block,注意清除浮动
  div.item   // 设置为 inline 或者 float,使其能流动
    img      // 设置定宽,高度自适应,间距等。

그리드 솔루션 설명

.wrap-waterfall--grid img{vertical-align: top;width: 100px}
.wrap-waterfall--grid .list{
    display: grid;
    grid-gap: 10px;
    /* 可以看到,网格大小,占据位置是需要提前设定的 */
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: minmax(50px, auto);
}
그리드가 어떤 경우에는 플렉스보다 사용하기 더 좋습니다. 예를 들어

행 제한을 돌파해야 하는데

아래 레이아웃과 같은 고정 레이아웃에만 적용되는 경우를 그리드를 사용하지 않고 어떻게 구현하겠습니까?

JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개

인터넷에서 GIRD에 의한 폭포 흐름 레이아웃을 구현하려는 계획이 있습니다

. 그러나 그 중 몇 가지를 컬러 블록이나 이미지 변형 및 자르기로 설정하는 것을 보았습니다. 계획은 nth-child를 사용하여 설정하는 것입니다. 키, 너무 무섭네요 .

Columns, flex CSS 구현

신뢰할 수 없는 솔루션위 솔루션과 비교하면 솔루션은 이미 수용 가능하지만 여전히 몇 가지 문제가 있습니다.

순서는 세로로 먼저, 그 다음 가로로
  • (columns) 호환성 문제
  • (flex)에 고정 높이를 부여해야 하며, 이는 설정된 열을 초과하여 설정된 열을 채우지 못합니다.
JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개 JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개 JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개 JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개
구성표 스크린샷
columns flex
JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개 1JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개
열 구성표

는 자연스럽게 지원되므로 설정만 하면 됩니다. 상위 항목으로 columns: 4; column-gap: 6px; .

columns: 4; column-gap: 6px;

flex 方案

flex-flow: column wrap;height: 2300px;flex 솔루션

flex-flow: column Wrap;height: 2300px; 기본적으로 가로 배열로 변경하고 줄바꿈을 허용하면 내용이 줄 바꿈됩니다. 고정 높이로.

절대 채널 높이 계산 체계신뢰할 수 있는 체계 체계절대잔여 채널높이 분할 채널 계산
헤드 스크린샷1JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개 1JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개 1JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개
🎜🎜🎜

这里的方案就靠谱起来了,可以满足我们使用要求。

我们来回忆一下我们的需求:展示一些内容,内容有特性定宽,不定高。不定高一般是因为内容长度或者高度不一致导致的,常见内容又分为两种文字和图片

  • 文字的话,在没有异步字体的情况下,可以理解为同步就可以获取到盒子高度。

  • 图片的话,因为加载是异步的,所以获取盒子的真实高度也是异步的。但是这里一般分为两种情况

  • 无高度,那么可以通过onload来监听图片加载完成。等图片加载完成再去获取高度。

  • 有高度,这种方案一般用在封面图、或者文章中,在上传图片的时候会保存原图尺寸,这个时候我们就可以直接使用已有数据。

获取图片高度

// 用于获取图片的真实高度
naturalHeight: 1180
// 用于获取图片的真实宽度
naturalWidth: 1200

//用户获取图片当前的渲染高度(会受 css 影响)
height: 98
//用户获取图片当前的渲染宽度(会受 css 影响)
width: 100

// 可返回浏览器是否已完成对图像的加载。如果加载完成,则返回 true,否则返回 fasle。
complete 属性
// 可以监听到图片加载完成的动作
onload

基于上面的内容,那我们可以先判断 complete 属性,

function getImageSize(img){
    if(img.complete){
        return Promise.resolve({
            naturalHeight: img.naturalHeight,
            naturalWidth: img.naturalWidth,
            height: img.height,
            width: img.width,
        })
    }else{
        return new Promise((resolve, reject)=>{
            img.addEventListener('load', ()=>{
                resolve({
                    naturalHeight: img.naturalHeight,
                    naturalWidth: img.naturalWidth,
                    height: img.height,
                    width: img.width,
                })
            })
        })
    }
}
/*
// 测试用例
el = document.createElement('img');
el.src = 'http://cors-www.lilnong.top/favicon.ico?'+Math.random()

getImageSize(el).then(console.log).catch(console.error)
setTimeout(()=>getImageSize(el).then(console.log).catch(console.error), 1000)
*/

absolute 计算高度方案

因为普通的布局已经无法满足我们的需求,所以我们可以考虑通过 position: absolute 来使内容通过绝对定位来显示

核心操作就是维护每个元素的 left、top,然后使用 left 和 top 去渲染到正确位置。

getListPosition(){
    // 视口宽度 / 每列宽度 得出划分为几列
    let col = this.screenWidth / this.itemWidth >> 0;
    var arr = [];
    for(var i = 0; i < col; i++) arr.push({
        list: [],
        height: 0,
    })
    // 遍历所有元素
    this.listInfo.forEach((item,idx)=>{
        // 找到最低的一列
        var colIndex = 0;
        for(var i = 1; i < col; i++){
            if(arr[colIndex].height > arr[i].height){
                // colItem = arr[i]
                colIndex = i
            }
        }
        // 修改元素的信息
        // 所属列
        item.line = colIndex;
        // 计算之后的 top 距离
        item.top = arr[colIndex].height+ &#39;px&#39;;
        // 计算之后的 left 距离
        item.left = colIndex * (this.itemWidth + 10) + &#39;px&#39;

        // 累加操作
        arr[colIndex].list.push(item);
        arr[colIndex].height += item.height + 10;
    })
    return arr
},

通过计算,我们可以到,瀑布流布局下每个元素的位置,通过绝对定位就可以实现。

根据下标,来渲染到不同的通道 idx % 4

因为上个方案用到了绝对定位,那么有没有不用绝对定位的方案呢?回到我们的问题点上 定宽,不定高,那我们完全可以通过分开渲染放弃 absolute 来实现。

jsGroupList(){
    return this.list.reduce((s,n,idx)=>{
        // 根据下标,直接分配所属列
        s[idx % 4].push({idx: idx, item: n})
        return s
    }, [[],[],[],[],])
},

看开头是实现类似的功能的,但是有一个弊端(快来评论区回复呀)。

通过高度计算,然后分通道,避免 absolute

因为上一个方案是按下标分类的,其实瀑布流是按高度分类的,所以我们分类条件换成最低的列。

jsGroupHeightList(){
    var list = [
        {height: 0, list: []},{height: 0, list: []},
        {height: 0, list: []},{height: 0, list: []},
    ]
    // 遍历每个元素
    for(var i = 0; i < this.list.length; i++){
        // 当元素有大小的时候在进行操作。
        if(!this.listInfo[i].height) return list;
        // 默认第一个通道是最小高度列
        var minHeightItem = list[0];
        // 计算最小高度列
        list.forEach(v=>{
            if(v.height < minHeightItem.height) minHeightItem = v
        })
        // 把新的元素高度累加到列中。
        minHeightItem.height += this.listInfo[i].height
        // 把新的元素push到列中
        minHeightItem.list.push({idx: i, item: this.list[i]})
    }
    return list;
},

总结

好了,到这里我能想到的方案就都介绍了。你还有什么方案吗?咱们可以在评论区讨论一下可行性。接下来就是我们的方案总结了。

方案 优点 缺点 点评
columns 实现简单、纯 CSS 方案 兼容性 -
flex - 需要固定高度,填充难以控制等问题 -
float、inline、bootstrapGrid - - 没点大都用不出这方案
grid - - 可以nth-child模拟实现、或者等待兼容性 masonry
absolute 效果好 - JS计算无限可能
js普通通道 - 填充难以控制 -
js优化通道 效果好、无绝对定位 在出现夸列等操作的时候不是很好控制 -

更多编程相关知识,请访问:编程入门!!

위 내용은 JS 또는 CSS를 사용하여 폭포 흐름 레이아웃을 구현하는 방법, 여러 솔루션 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제