ホームページ  >  記事  >  ウェブフロントエンド  >  JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介

JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介

青灯夜游
青灯夜游転載
2021-07-16 19:45:002617ブラウズ

この記事では、ウォーターフォール フローのレイアウトを説明し、信頼できる 3 つの JS ソリューションと信頼できない CSS ソリューションを 3 つ紹介します。一定の参考値があるので、困っている友達が参考になれば幸いです。

JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介

実用性の精神で、今日は ウォーターフォール フロー レイアウト (昨日、弟に作り方を尋ねられました。長い間探しても見つかりませんでした。どうやらイントラネット ) に書かれていたことが分かりました。

デモ アドレス: http://www.lilnong.top/static/html/waterfall.html

ウォーターフォール フロー レイアウトとは何ですか?

たとえば、huapetal.comMogujie (以下に写真を掲載しました) では、これらの Web サイトはコンテンツを表示するときにウォーターフォール フロー レイアウトを使用します。

デザインドラフトを表示するページも作成したいと考えています (固定幅、可変高さ)。ウォーターフォール フローは優れたソリューションです。

ウォーターフォール フロー レイアウトの核心はグリッド レイアウトに基づいており、各行に含まれる項目リストの高さはランダムです (高さは独自のコンテンツに応じて動的に変化します)。リストはスタックに配置されます。最も重要なことは、スタック間に不要なスペースがないことです。上の写真を見て、私たちが話している滝の流れのレイアウトがどのようなものかを見てみましょう。

#ウェブサイトMogujie花ペットネットJDVVスクリーンショット スキームサブチャネル絶対
JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介 JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介 JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介 JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介


##grid、inline、float

Magic solution は、本質的には純粋な CSS ソリューションとみなすこともできます。 is

文書の流れに応じて

、左から右、上から下へ。

#スキームgridinlinefloatbootstrap-gridスクリーンショット

ドキュメント フロー レイアウトには、非常に明白な line という概念があり、行を伸ばすと空白が残り、行は重なりません。ここで最も不思議なのは、フロートのレイアウトです。

DOM 構造

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

grid ソリューションの説明

.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);
}
grid は、場合によっては flex よりも使用する方が適しています。たとえば、

行制限を突破する必要があります

が、これは以下のレイアウトなどの固定レイアウトにのみ適用されます。グリッドを使用しない場合は、どのように実装しますか?

JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介

gird がウォーターフォール フロー レイアウトを実装する計画があります

が、カラー ブロックや画像の変形とトリミングが含まれているものをいくつか見ました。高さの設定には nth-child を使用します。 は怖すぎます

列、フレックス CSS 実装

信頼性の低いソリューション も純粋な CSS ソリューションです。上記のソリューションと比較すると、このソリューションは許容可能ですが、まだいくつか問題があります。

順序は最初に垂直、次に水平です
  • (列)互換性の問題
  • (フレックス)には固定の高さを与える必要があり、設定された列は設定値を超えており、設定欄は入力できません。
JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介 JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介 JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介 JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介
スキームスクリーンショット
フレックス
JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介 1JSやCSSを使ってウォーターフォールフローレイアウトを実装する方法、いくつかの解決策を紹介
列スキーム

は当然サポートされており、親の

columns: 4; column-gap: 6px;

に設定するだけで済みます。

フレックス スキーム

flex-flow: 列の折り返し;高さ: 2300px;

デフォルトは水平配置ですが、垂直配置に変更できます。配置と折り返しを許可し、コンテンツを固定の高さで折り返します。 絶対チャネル高さ計算スキーム

信頼性の高いスキーム

## スキームabsolute残りのチャンネル高さチャンネルの計算ヘッドのスクリーンショット
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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。