タイル状に可変グリッドレイアウトを簡単に実装できる、今や定番のjqueryプラグインといえば「Masonry」。
しかし、このMasonryには配置したアイテムを指定したタグを持つもののみ表示するフィルター機能や、目的別に並べ替えるソート機能がありません。
「Masonry」プラグインのこれらの弱点を補ってくれる代替のプラグインとして有名なのが、「isotope」というjQueryプラグインがありますが、こちらは商用利用の場合はライセンス料の支払いが必要となってしまいます。
そこで今回紹介するのは、フィルター機能もソート機能も搭載した可変グリッドレイアウトを実現し、レスポンシブにも対応した、無料で商用利用も可能なJavascriptプラグイン「Muuri」(GitHubはこちら)。
MITライセンスで、IE9〜をサポートしています。
なお、Masonryは単体で利用可能で圧縮された状態のファイルサイズが 30KB なのに対して、Muuriは圧縮状態のファイルサイズが 40KB で、アニメーション用に Web-Animations.js(minified時で47KB前後)、ドラッグ用に Hammer.js(minified時で45KB前後) という外部スクリプトが場合によっては必要となります。
ただし、MasonryはjQueryが前提ですが、MuuriはjQueryは不要です。
最もシンプルな実行例
フィルターもソートもドラッグも考慮せず、すべてデフォルトのパラメータで最もシンプルなコードだけ(new Muuri(selector);
)で可変グリッドレイアウトを表示した場合のデモがこちら。
See the Pen
Grid layout sample #1 by muuri.js by digistate (@digistate)
on CodePen.
INDEX
基本構成
下準備
「Muuri」は、単体のスクリプトのみでも十分機能しますが、内部アニメーションとアイテムをドラッグ可能にするには、それぞれ以下のスクリプトを先に読み込む必要があります。
内部アニメーションを行うためのスクリプト
「Web-Amination.js」をロードします。
<script src="web-animations.min.js"></script> <!-- CDN経由の場合 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/web-animations/2.3.1/web-animations.min.js"></script>
ドラッグ操作を有効にする場合のスクリプト
「Hammer.js」をロードします。
<script src="hammer.min.js"></script> <!-- CDN経由の場合 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
必要に応じて上記のスクリプトをロードしてから、メインの「Muuri」をロードします。
<script src="muuri.min.js"></script>
HTMLマークアップ
基本となるマークアップは以下のとおり。
<!-- コンテナ --> <div class="grid"> <!-- アイテム1 --> <div class="item"> <div class="item-content"> <!-- カスタムコンテンツ開始 --> カスタムコンテンツ <!-- カスタムコンテンツ終了 --> </div> </div> <!-- アイテム2 --> <div class="item"> <div class="item-content"> <!-- カスタムコンテンツ開始 --> <div class="my-custom-content"> Yippee! </div> <!-- カスタムコンテンツ終了 --> </div> </div> : </div>
まず、このマークアップでは全体を括るコンテナ要素に .grid
というセレクタが付けられていて、「Muuri」には初期化の際にこのセレクタを渡すだけで可変グリッドレイアウトを構成してくれます。
.grid
の中には、各アイテム(タイル)を構成する単位となる .item
があり、これは配置を行う対象として必要です。
さらに、.item
の内部には .item-content
があり、これはアイテムの可視化のアニメーションを行うために必要となります。
実際に表示したいアイテムごとのカスタムコンテンツは、この .item-content
の中に記述し、アイテム用のCSSも、この .item-content
か、この内部のカスタムコンテンツに対してスタイリングするようにします。
また、グリッドレイアウトを構成するには、アイテムが最低2つは必要となります。
CSS
最低限指定が必要なCSSもたったこれだけで済みます。
/* グリッドレイアウトのコンテナ */ .grid { position: relative; } /* アイテム */ .item { display: block; /* 必須 */ position: absolute; /* 必須 */ width: 100px; /* アイテムの幅 */ height: 100px; /* アイテムの高さ */ margin: 5px; /* アイテム間のマージン(この2倍になる) */ z-index: 1; }
アイテム要素(.item
)には、display:block
と position:absolute
は必ず指定しておきます。
あとは、基準とするコンテナ要素の幅に何グリッド分に分割するかを決めて、グリッドの最小単位となる幅(width)と、必要に応じてアイテム間のマージンを算出してスタイリングします。
今回のサンプルでは、この記事に埋め込まれる幅を基準とするため、コンテナである .grid
には width を指定し、margin でセンタリングしています。
.grid { position: relative; width:878px; max-width:100%; margin:0 auto; }
レスポンシブ化(メディアクエリ)
「Muuri」によるグリッドレイアウトは、表示幅が狭くなっても、オーバーフローせずにアイテムがアニメーションしながら下方に並んで再配置されるようになっていますが、元のコンテナ幅を基準にしたアイテムサイズのままであるため、レイアウトが可変した際に右側に余白ができてしまいます。
コンテナ幅以下になった場合は、CSSのメディアクエリで改めてアイテムサイズをリサイズして、表示幅にフィットするようにレスポンシブに対応させてみます。
/* 877ピクセル幅以下になったら3カラム化 */ @media ( max-width : 877px ){ .item{ width:calc(33.33% - 11px); height:calc(33.33vw - 11px); } } /* 640ピクセル幅以下になったら2カラム化 */ @media ( max-width : 640px ){ .item{ width:calc(50% - 10px); height:calc(50vw - 10px); } }
Javascript
HTMLのマークアップと、先述の最低限のCSSだけ整えば、以下のJavascriptの1行だけで可変グリッドレイアウトが表示されます。
var grid = new Muuri('.grid');
アイテムのドラッグを有効にする
グリッドレイアウトの各アイテムをドラッグして入れ替え可能にするには、まずは先述の hammer.js を読み込むようにしておき、「Muuri」の初期化の際にドラッグを有効にするようオプションパラメータをセットしておきます。
var grid = new Muuri('.grid', { dragEnabled: true });
オプションとして、たった dragEnabled: true
を指定するのみでOKです。
その他、指定可能なドラッグ機能に関する細かなオプションについてはこちら。
また、ドラッグ中は他のアイテムよりも前面にさせる必要があるため、ドラック中に自動的に対象アイテムに挿入されるセレクタ(.muuri-item-dragging
)に対して、z-index
を指定しておきます。
.item.muuri-item-dragging { z-index: 3; }
ドラッグ操作を有効にした場合のデモ
See the Pen
Grid layout sample #2 by muuri.js (Enable dragging) by digistate (@digistate)
on CodePen.
フィルター/ソート機能を実装する
「Muuri」で表示するグリッドレイアウトに、フィルター機能を反映するには、まずはアイテムごとにグルーピングするための「タグ付け」をしておきます。
そうすることで、「Muuri」は同じ「タグ」を持つアイテムのみをフィルタリングして表示してくれます。
フィルタリングのための準備
「タグ付け」の方法は、2種類あります。
classにタグ用のセレクタを含める
.item
要素の class にタグとなる任意のセレクタ(文字列)を含めて、これをフィルタリングのキーとする場合は、以下のコードで「Muuri」で生成したグリッドレイアウトのオブジェクトにフィルターを実行させることができます。
アイテムのマークアップ
<div class="item foo"> <div class="item-content"> Item 1 </div> </div>
Javascript
var grid = new Muuri('.grid'); // foo というセレクタを持つアイテムのみを表示 grid.filter('.foo');
data属性によるタグ付け
classの場合は、スペースを含む場合やclassの値に含められないものをタグにする必要がある場合は不向きです。
このような場合は、.item
要素に任意の data属性を設けてタグ付けを行い、「Muuri」のfilterメソッドにそのdata属性の値を渡すことでフィルタリングが可能になります。
var grid = new Muuri('.grid'); // data-color属性の値に「red」を持つアイテムのみを表示 grid.filter(function(item){ var element = item.getElement(); return element.getAttribute('data-color') === 'red'; });
これを応用して、フォーム要素にフィルタリング対象となるvalue
を持たせて、例えばselect
要素のイベントリスナーを登録して、選択されたoption
要素のvalue
値と、アイテムのdata属性の値が一致する場合のみtrueを返してフィルタリングさせることができるようになります。
フィルター(検索含む)/ソート機能を実装した場合のデモ
以下のデモでは、フォーム(select
)要素に予めフィルタリングのための「タグ」がセットされた絞り込みに加え、検索ワードのフォーム(input
)要素がありますが、それぞれにイベントリスナーがあり、処理自体はどちらも同じ grid.filter
メソッドでフィルタリングしているだけです。
ただし、select
要素の場合は、data-color
属性、検索ワード(input
) の場合は、data-title
という属性の値を比較対象にしています。
See the Pen
Grid layout sample #3 by muuri.js (Filter/Sort) by digistate (@digistate)
on CodePen.
その他、オプションパラメータ、グリッドメソッド、アイテムメソッド、イベントなど、かなり豊富な種類があるので、細かな要件や非常に凝った可変グリッドレイアウトコンテンツにもほぼ対応できそうです。