中文字幕一区二区三区在线中文-日本中文字幕 在线观看-欧美日韩国产亚洲综合-性色AV一二三天美传媒

廣州總部電話:020-85564311
20年
互聯(lián)網(wǎng)應(yīng)用服務(wù)商
廣州總部電話:020-85564311
20年
互聯(lián)網(wǎng)應(yīng)用服務(wù)商
請輸入搜索關(guān)鍵詞
知識庫 知識庫

優(yōu)網(wǎng)知識庫

探索行業(yè)前沿,共享知識寶庫

如何實現(xiàn)跨瀏覽器的CSS Masonry布局

發(fā)布日期:2025-08-08 17:55:07 瀏覽次數(shù): 814 來源:前端小石匠
推薦語
跨瀏覽器CSS Masonry布局終于有了完美解決方案!僅需66行JavaScript即可實現(xiàn)靈活響應(yīng)式磚塊布局。

核心內(nèi)容:
1. 當(dāng)前各瀏覽器對CSS Masonry的原生支持現(xiàn)狀與分歧
2. 僅66行JS實現(xiàn)的跨瀏覽器解決方案核心原理
3. 與Tailwind結(jié)合使用的實戰(zhàn)技巧與完整代碼示例
小優(yōu) 網(wǎng)站建設(shè)顧問
專業(yè)來源于二十年的積累,用心讓我們做到更好!

CSS - Implementing Responsive Masonry Layouts许多CSS专家去年对新的砖块式布局功能的可能语法进行了深入讨论。当时存在两个主要阵营和一个在两者之间取得平衡的第三个阵营:

  • 使用 display: masonry
  • 使用 grid-template-rows: masonry
  • 使用 item-pack: collapse

我认为他们还没有得出结论。但您可能需要知道的是,Firefox已经使用第二种语法支持砖块式布局。而Chrome正在使用第一种语法进行测试。虽然看到CSS Masonry的原生支持正在发展是一件很酷的事情,但如果其他浏览器不支持相同的实现,我们就真的无法在生产中使用它……

因此,与其加入其中一个阵营,我继续研究如何在其他浏览器中实现砖块式布局。我很高兴地报告我找到了一种方法——而且,额外奖励!——支持可以通过仅66行JavaScript提供。

在这篇文章中,我将向您展示它是如何工作的。但首先,这里有一个供您玩的演示,只是为了证明我并没有胡说八道。请注意,由于我们正在等待图片加载,会有轻微的延迟。如果您在顶部折叠处放置砖块式布局,请考虑不包括图片,因为这样!

这是什么魔法?

现在,这个演示中包含了很多东西,尽管只有66行JavaScript:

  • 您可以定义任意数量的列的砖块式布局。
  • 每个项目可以跨越多列。
  • 我们在计算每个项目的大小之前等待媒体加载。
  • 我们通过监听与ResizeObserver的变化使其具有响应性。

这些使我的实现非常健壮,适合生产使用,而且比互联网上许多Flexbox砖块式布局更灵活。

现在,一个提示。 如果您将其与Tailwind的响应式变体和任意值结合使用,您可以在不编写更多CSS的情况下将更多灵活性纳入这个砖块式网格。

好吧,在你更加兴奋之前,让我们回到主要问题:这到底是怎么工作的?

让我们从补丁开始

Firefox已经通过第二个阵营的语法支持砖块式布局。这是您需要在Firefox中创建CSS砖块式网格布局的CSS。

.masonry {
  display: grid;
  grid-template-columnsrepeat(
    auto-fit,
    minmax(min(var(--item-width, 200px), 100%), 1fr)
  );
  grid-template-rows: masonry;
  grid-auto-flow: dense; /* 可选,但建议 */
}

由于Firefox已经具有原生的砖块式支持,我们自然不应该干扰它。检查砖块式是否默认支持的最好方法是检查grid-template-rows是否可以持有masonry值。

function isMasonrySupported(container) {
  return getComputedStyle(container).gridTemplateRows === 'masonry'
}

如果砖块式受支持,我们将跳过我们的实现。否则,我们将采取一些措施。

const containers = document.querySelectorAll('.masonry')

containers.forEach(async container => {
  if (isMasonrySupported(container)) return
})

简单的砖块式布局

现在,我想先声明一下,我并不是发明这项技术的人。

当我浏览网页,寻找实现砖块式网格的方法时,我发现了这项技术。所以,称赞一下第一个开发这个想法的未知开发人员——也许还有我,因为我理解、转换并使用了它。

这项技术是这样的:

  1. 我们将grid-auto-rows设置为0px
  2. 然后,我们将row-gap设置为1px
  3. 然后,我们通过getBoundingClientRect获取项目的宽度。
  4. 然后,我们将项目的“行分配”大小通过将width值与column-gap值相加来确定。

这对于那些按照标准方式使用CSS Grid的人来说真的不直观。但一旦你理解了这一点,你也可以理解它是如何工作的!

现在,由于这一点很不直观,我们将一步一步地讲解,让您看到整个过程如何演变成最终输出。

逐步讲解

首先,我们将grid-auto-rows设置为0px。这很奇怪,因为每个网格项目实际上都有“零高度”。但同时,CSS Grid保持列和行的顺序!

containers.forEach(async container => {
  // ...
  container.style.gridAutoRows = '0px'
})

其次,我们将row-gap设置为1px。一旦我们这样做,您开始注意到行之间有一个初始堆叠,每个行都在前一个行下方一像素。

containers.forEach(async container => {
  // ...
  container.style.gridAutoRows = '0px'
  container.style.setProperty('row-gap''1px''important')
})

第三,假设网格项目中没有图片或其他媒体元素,我们可以轻松地使用getBoundingClientRect获取每个网格项目的高度。

然后,我们可以通过将grow-row-end替换为height值来在CSS Grid中恢复网格项目的高度。这是因为每个row-gap现在都是1px高。

当我们这样做时,您可以看到网格开始成形。每个项目现在(有点)回到了它们各自的位置:

containers.forEach(async container => {
// ...
let items = container.children
layout({ items })
})

functionlayout({ items }) {
  items.forEach(item => {
    const ib = item.getBoundingClientRect()
    item.style.gridRowEnd = `span ${Math.round(ib.height)}`
  })
}

现在,我们需要恢复项目之间的行间隙。幸运的是,由于砖块式网格通常具有相同的column-gaprow-gap值,我们可以通过读取column-gap值来获取所需的行间隙。

一旦我们这样做,我们将它添加到grid-row-end中,以扩展项目在网格中占据的行数(即“高度”):

containers.forEach(async container => {
// ...
const items = container.children
const colGap = parseFloat(getComputedStyle(container).columnGap)
layout({ items, colGap })
})

functionlayout({ items, colGap }) {
  items.forEach(item => {
    const ib = item.getBoundingClientRect()
    item.style.gridRowEnd = `span ${Math.round(ib.height + colGap)}`
  })
}

就这样,我们制作了砖块式网格!从现在开始,所有内容都是为了使这个准备好用于生产。

等待媒体加载

尝试向任何网格项目添加图片,您会注意到网格会中断。这是因为项目的宽度将是“错误的”。

这是因为在图片正确加载之前,我们获取了height值。DOM还不知道图片的尺寸。为了解决这个问题,我们需要在运行layout函数之前等待媒体加载。

我们可以使用以下代码完成此操作(由于这不是CSS技巧,我将不解释):

containers.forEach(async container => {
// ...
try {
    awaitPromise.all([areImagesLoaded(container), areVideosLoaded(container)])
  } catch(e) {}

// 图片加载后运行布局函数
layout({ items, colGap })
})

// 检查图片是否加载
asyncfunctionareImagesLoaded(container) {
const images = Array.from(container.querySelectorAll('img'))
const promises = images.map(img => {
    returnnewPromise((resolve, reject) => {
      if (img.completereturnresolve()
      img.onload = resolve
      img.onerror = reject
    })
  })
returnPromise.all(promises)
}

// 检查视频是否加载
functionareVideosLoaded(container) {
const videos = Array.from(container.querySelectorAll('video'))
const promises = videos.map(video => {
    returnnewPromise((resolve, reject) => {
      if (video.readyState === 4returnresolve()
      video.onloadedmetadata = resolve
      video.onerror = reject
    })
  })
returnPromise.all(promises)
}

,我们有一个可以与图片和视频一起工作的CSS砖块式网格!

使其具有响应性

这是一个简单的步骤。我们只需要使用ResizeObserver API来监听砖块式网格容器的尺寸的任何变化。

当发生变化时,我们再次运行layout函数:

containers.forEach(async container => {
// ...
const observer = new ResizeObserver(observerFn)
observer.observe(container)

function observerFn(entries) {
  for (const entry of entries) {
    layout({colGap, items})
  }
}
})

这个演示使用了标准的Resize Observer API。但您可以使用我们前几天构建的精简的resizeObserver函数使其更简单。

containers.forEach(async container => {
  // ...
  const observer = resizeObserver(container, {
    callback () {
      layout({colGap, items})
    }
  })
})

基本上就是这样!现在您有一个可以在支持CSS Grid的每个浏览器中使用的健壮的砖块式网格!

令人兴奋,不是吗?这个实现非常简单易用!

使用Splendid Labz的砖块式网格

如果您不反对使用他人编写的代码,也许您可以考虑在Splendid Labz中获取我为您构建的砖块式网格。

为此,请安装辅助库并添加必要的代码:

# 安装库
npm install @splendidlabz/styles
/* 导入所有布局代码 */
@import '@splendidlabz/layouts';
// 使用砖块式脚本
import { masonry } from '@splendidlabz/styles/scripts'
masonry()

最后一件事情:我一直构建了大量工具,以帮助使网页开发对我们每个人来说都更容易。我将它们全部放在Splendid Labz品牌下——而今天我向您展示的砖块式网格就是这些示例之一。

如果您喜欢这个,您可能对其他使布局变得超级简单的布局工具感兴趣。

希望您今天喜欢这篇文章。如果您愿意,请释放您的新CSS砖块式网格,祝您一切顺利!


· · ·

原文地址:https://css-tricks.com/making-a-masonry-layout-that-works-today/
作者:Zell Liew

優(yōu)網(wǎng)科技,優(yōu)秀企業(yè)首選的互聯(lián)網(wǎng)供應(yīng)服務(wù)商

優(yōu)網(wǎng)科技秉承"專業(yè)團隊、品質(zhì)服務(wù)" 的經(jīng)營理念,誠信務(wù)實的服務(wù)了近萬家客戶,成為眾多世界500強、集團和上市公司的長期合作伙伴!

優(yōu)網(wǎng)科技成立于2001年,擅長網(wǎng)站建設(shè)、網(wǎng)站與各類業(yè)務(wù)系統(tǒng)深度整合,致力于提供完善的企業(yè)互聯(lián)網(wǎng)解決方案。優(yōu)網(wǎng)科技提供PC端網(wǎng)站建設(shè)(品牌展示型、官方門戶型、營銷商務(wù)型、電子商務(wù)型、信息門戶型、微信小程序定制開發(fā)、移動端應(yīng)用(手機站、APP開發(fā))、微信定制開發(fā)(微信官網(wǎng)、微信商城、企業(yè)微信)等一系列互聯(lián)網(wǎng)應(yīng)用服務(wù)。


我要投稿

姓名

文章鏈接

提交即表示你已閱讀并同意《個人信息保護聲明》

專屬顧問 專屬顧問
掃碼咨詢您的優(yōu)網(wǎng)專屬顧問!
專屬顧問
馬上咨詢
聯(lián)系專屬顧問
聯(lián)系專屬顧問
聯(lián)系專屬顧問
掃一掃馬上咨詢
掃一掃馬上咨詢

掃一掃馬上咨詢

和我們在線交談!