Masonry

Masonry

Masonry 是一個自動佈局(Layout)垂直空間不同尺寸區塊的套件,它就像堆砌磚頭那樣將元素區塊一塊一塊相疊,例子:Pinterest。搭配 imagesloaded 套件可以形成網站設計中的瀑布流技術。

需要套件 CDN

需要 jQuery、Masonry、imagesloaded 三種套件。在載入時會導致子元素佈局重疊,imagesLoaded 套件可以解決這個問題,使用方式在下方完整範例。

<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
<script src="https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.min.js"></script>

npm 安裝方式

npm install masonry-layout

概念

設定父元素 .grid 底下的子元素 .grid-item 讓它們具有自動佈局的效果。所以套件重點都在這兩個 class 設定,也可以使用其他名稱,id 或 class 都可以。

設定

Masonry 所有設定都是可選的,官方建議 columnWidth、itemSelector 要設定。

itemSelector

為指定的子元素,也就是 .grid-item。.grid-item 為 Masonry 主要控制的對象,你可以為這些子元素設定寬度、高度。官方表示子元素項目的 CSS 由自己設計。

columnWidth

子元素 .grid-item 的寬度,可設定數字。對具有百分比寬度的響應式佈局使用元素大小調整。設置 columnWidth 為元素或選擇器字符串,以使用元素的外部寬度作為寬度大小。

官方建議設置 columnWidth。如果 columnWidth 未設置,則砌體將使用第一個項目的外部寬度。

percentPosition

以百分比值而非像素值設置項目位置。與百分比寬度的子元素配合得很好,如果要使用響應式佈局,.grid-item 要設定為百分比,並且將設定選項的percentPosition: true打開。

gutter

設定子元素 .grid-item 水平之間的距離,bootstrap 此項不需設定(如果與欄位系統綁在一起),也就是 .grid-item 與 .col 欄位都在同一個元素,這是因為 .col 欄位空間都已經分配完畢,若再設定 gutter 會導致欄位換行。如果要在元素之間設置垂直空間,請使用 CSS margin

horizontalOrder

horizontalOrder 設定為 true,對項目進行佈局以(大部分)保持水平的從左到右的順序。

stamp

推擠子元素的效果。請見設定

originLeft

true,設置子元素從左至右的佈局。

originTop

true,設置子元素從上至下的佈局。

containerStyle

應用於容器元素的 CSS 樣式,預設為containerStyle:{ position: 'relative' }

transitionDuration

子元素轉場持續時間,預設是transitionDuration: '0.4s'

stagger

子元素轉場錯開時間,單位毫秒。

resiz

調整窗口大小時調整大小和位置。預設 resize: true。

initLayout

在初始化時啟用佈局。預設 initLayout: true。

方法

方法是由實體完成的動作。

.masonry()

設定所有子元素的選項設定。參數字串 ‘layout’ 是當某個子元素尺寸變動,可以設定 ‘layout’ 讓所有項目重新佈局。

// 設定子元素項目
var $grid = $('.grid').masonry({
itemSelector: '.grid-item',
columnWidth: '.grid-item'
})
// 當觸發 gigante 類別時,改變子元素的尺寸
$grid.on('click', '.grid-item', function () {
$(this).toggleClass('gigante')
// 重新佈局
$grid.masonry('layout')
})

更多方法請參考官網

完整範例

<!-- Animate.css -->
<link rel="stylesheet" href="css/animate.css" />
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="css/bootstrap.css" />
<style>
.grid {
background: pink;
}

.grid-item img {
display: block;
max-width: 100%;
}

.row > div {
padding: 0;
/* padding: 5px; */
}

.card {
padding: 5px;
margin: 0 5px;
}

.grid-item {
margin-bottom: 10px;
}
</style>

<div class="container">
<div class="row grid">
<div class="col-sm-6 col-md-3 col-lg-4 grid-item">
<div class="card">
<img class="lazyload" src="./images/01.jpg" />
</div>
</div>
<div class="col-sm-6 col-md-3 col-lg-4 grid-item">
<div class="card">
<img class="lazyload" src="./images/02.jpg" />
</div>
</div>
<div class="col-sm-6 col-md-3 col-lg-4 grid-item">
<div class="card">
<img class="lazyload" src="./images/03.jpg" />
</div>
</div>
<div class="col-sm-6 col-md-3 col-lg-4 grid-item">
<div class="card">
<img class="lazyload" src="./images/04.jpg" />
</div>
</div>
<div class="col-sm-6 col-md-3 col-lg-4 grid-item">
<div class="card">
<img class="lazyload" src="./images/05.jpg" />
</div>
</div>
<div class="col-sm-6 col-md-3 col-lg-4 grid-item">
<div class="card">
<img class="lazyload" src="./images/06.jpg" />
</div>
</div>
<div class="col-sm-6 col-md-3 col-lg-4 grid-item">
<div class="card">
<img class="lazyload" src="./images/07.jpg" />
</div>
</div>
<div class="col-sm-6 col-md-3 col-lg-4 grid-item">
<div class="card">
<img class="lazyload" src="./images/08.jpg" />
</div>
</div>
<div class="col-sm-6 col-md-3 col-lg-4 grid-item">
<div class="card">
<img class="lazyload" src="./images/09.jpg" />
</div>
</div>
</div>
</div>
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="js/jquery-3.5.1.min.js"></script>
<script src="js/popper.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<!-- others -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/wow/1.1.2/wow.min.js"></script>
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
<script src="https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.min.js"></script>

<script>
// jQuery + masonry + imagesLoaded + wow
new WOW().init()
// imagesLoaded 的 background 可針對背景的對象圖片進行偵測,true 為選擇器所有圖片,也可以針對子元素的 selector,例如 .lazyload
$('.grid')
.imagesLoaded({background: '.lazyload'}, function () {
const $grid = $('.grid').masonry({
itemSelector: '.grid-item', // 選擇要排列的子元素
columnWidth: '.grid-item', // 子元素寬度,可為數字,RWD 可以設定子元素 .grid-item 選擇器名稱
percentPosition: true, // RWD 百分比設定選項
transitionDuration: '0.5s', // 子元素轉場持續時間,預設'0.4s'
stagger: 0, // 子元素轉場錯開時間,單位毫秒
isAnimated: true
})
})
.done(function (instance) {
console.log('all images have been successfully loaded')
})
.fail(function () {
console.lgo('have a fail')
// progress 每當一個圖片載入會觸發
})
.progress(function (instance, image) {
$('.grid-item').addClass('wow slideInUp')
console.log('elm:' + instance, 'img:' + image.img.src)
})
.always(function (instance) {
console.log('all images have been loaded')
})

// Masonry 的事件,完成後可做的事情
$('.grid').on('layoutComplete', function (event, laidOutItems) {
console.log(event)
console.log('Masonry layout completed on ' + laidOutItems.length + ' items')
})
</script>