大学生からの Web 開発

会社の人に見つかってぽよぽよしてきた

Masonry を使って要素が重なってしまったときの対処法

f:id:karur4n:20140216172325p:plain

可変のグリッドレイアウトを実現できる JS ライブラリ、 Masonry は非常に便利でお世話になっているのだが、問題が起こって解決したのでメモ。

問題

以下のように、画像をラップしたブロックを Masonry で配置すると画像の高さが反映されずにブロックが重なって表示されてしまう。

<div class="container">
    <div class="item">
        <img src="sample1.jpg">
        <p>hoge</p>
    </div>
    <div class="item">
        <img src="sample2.jpg">
        <p>fuga</p>
    </div>
    <div class="item">
        <img src="sample3.jpg">
        <p>piyo</p>
    </div>
</div>
var container = document.querySelector('.container');
var msnry = new Masonry( container, {
  // options
  columnWidth: 200,
  itemSelector: '.item'
});

解決法

その1 画像の表示サイズが固定の場合

画像の高さを固定して表示する場合は、属性で高さを指定すればよい。

<div class="container">
    <div class="item">
        <img src="sample1.jpg" height="100" width="200">
        <p>hoge</p>
    </div>
    <div class="item">
        <img src="sample2.jpg" height="120" width="200">
        <p>fuga</p>
    </div>
    <div class="item">
        <img src="sample3.jpg" height="500" width="200">
        <p>piyo</p>
    </div>
</div>

だいたいみんな画像にサイズは指定しているのでぶっちゃけこの問題に遭遇することはないと思う。大事なのは次。

その2 画像のサイズを可変にする場合

レスポンシブデザインのために Media Queries で画像のサイズを可変にしたいとする。そうすると上の例のように、属性でサイズを指定することはできない。

この場合は、imagesloaded を使う。これは指定した要素中の画像が読み込み終わったイベントを発火してくれるものだ。

var container = document.querySelector('.container');

imagesLoaded(container, function () {
  var msnry = new Masonry(container, {
    columnWidth: 200,
    itemSelector: '.item'
  });
});

こう書くと Masonry が配置するときには画像のロードが終わっていて高さが取得されているので、要素が重なることはない。

あとはこんな感じで書けば、画像のサイズを可変にできる。

@media screen and (max-width: 1000px) {
  .item img{
    width: 200px;
  }
}
@media screen and (max-width: 760px) {
  .item img{
    width: 150px;
  }
}
@media screen and (max-width: 480px) {
  .item img{
    width: 100px;
  }
}
@media screen and (max-width: 320px) {
  .item img{
    width: 50px;
  }
}

参考

jQuery Masonryを使う際にわりと大事なimagesLoadedプラグイン | WEB SHOWZINE