CSS Grid Layout Module 格線佈局 (2) Masonry 瀑布流應用

上一篇文章 介紹了 CSS Grid,接下來運用網格系統來實作瀑布流版面。

瀑布流(Waterfall Flow)是一種網頁佈局的設計方式。瀑布流的特點是將內容項目垂直排列,並根據可用的空間進行自適應調整,形成像瀑布一樣的流動效果 。

瀑布流佈局中,每個元素的寬度通常是固定的,但高度會根據內容的大小變化。這樣可以使元素在垂直方向上緊密堆疊,填滿可用空間。當一列的空間被填滿後,下一個元素會自動排列到空間較少的列中,達到均衡的排版。

透過 CSS Grid 或 Flexbox 可以達成瀑布流佈局的效果,本篇會使用 CSS Grid 搭配 JavaScript 來完成實作。

廣告

本篇作法無法達成轉場效果,如果想讓畫面轉換更加流暢,可以參考 這篇文章(masonry-layout 套件運用)

概念解析

利用 CSS Grid 格線系統來達成瀑布流的效果:

  • grid-auto-rows 設定列高
  • grid-gap 建立網格間距
  • 利用 Javascript 取得元素的高度,並計算 grid-row-end 屬性
  • 利用網格系統,每個元素會去找到空間使用最少的列,並排列在其後

格線的結構如下圖:

HTML

  • 外層容器 .container
  • 內層元素 .item
<ul class="container">
<li class="item">
<div class="content">
<h3>1.</h3>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsam voluptatibus hic laborum ea maiores, harum nobis. Placeat numquam ad laboriosam esse est porro, cum deserunt velit libero beatae quam necessitatibus. Iste sapiente commodi est labore amet quae rerum magni! Alias eum molestias sint nostrum optio ipsam quia delectus sunt. Rerum
</div>
</li>
<li class="item">
<div class="content">
<h3>2.</h3>
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Voluptatibus dolore natus ea
</div>
</li>

...

<li class="item">
<div class="content">
<h3>16.</h3>
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Sequi itaque veniam at labore consequuntur dicta adipisci ut laudantium deserunt
</div>
</li>
</ul>

CSS

外層容器

  • auto-fill:搭配 repeat(count, value) 函式使用,根據可用空間填滿欄或列
  • minmax(min-value, max-value):指定範圍最小與最大值,自動調整欄或列的尺寸
.container {
display: grid;
grid-gap: 1rem;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-auto-rows: 1rem;
}

內層元素

  • grid-row-end:透過 Javascript 動態計算

Javascript

  • rowHeight:取得 grid-auto-rows
  • rowGap:取得 grid-row-gap
  • 透過 getBoundingClientRect().height 取得元素的高度
  • 利用以上值計算元素 grid-row-end: span <number> 表示所佔列數,根據起始位置往後推算
  • 監聽螢幕 resize 事件,重新計算元素高度

getBoundingClientRect().height vs offsetHeight:
getBoundingClientRect().height 取得的是相對於螢幕視窗的可視高(渲染後的結果),而 offsetHeight 取得的是元素完整高,getBoundingClientRect().height 會受到 transform 影響,例如元素設定高度 100px 以及 transform: scale(0.5);,getBoundingClientRect().height 得到 50,而 offsetHeight 得到的是 100

const grid = document.querySelector(".container");
const style = window.getComputedStyle(grid);
const allItems = document.querySelectorAll(".item");

const resizeGridItem = (item) => {
rowHeight = parseInt(style.getPropertyValue("grid-auto-rows"));
rowGap = parseInt(style.getPropertyValue("grid-row-gap"));
rowSpan = Math.ceil((item.querySelector(".content").getBoundingClientRect().height + rowGap) / (rowHeight + rowGap));
item.style.gridRowEnd = `span ${rowSpan}`;
}

const resizeAllGridItems = () => {
allItems.forEach(ele => {
resizeGridItem(ele);
});
}

window.onload = resizeAllGridItems();
window.addEventListener("resize", resizeAllGridItems);

範例程式碼


參考文章:

https://css-tricks.com/piecing-together-approaches-for-a-css-masonry-layout/
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout
https://medium.com/@andybarefoot/a-masonry-style-layout-using-css-grid-8c663d355ebb

廣告
CSS Grid Layout Module 格線佈局 (1) 完整介紹與範例 CSS Grid Layout Module 格線佈局 (3) Responsive Table 響應式表格應用

評論

廣告
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×