CSSだけでMasonryレイアウト

## この記事の概要

[Pinterest](https://www.pinterest.com/)に代表されるMasonryレイアウト、実現したいと思ったことはありませんか？

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/3baa7570-1776-eb32-eeff-9f33919a4ff3.png)

このレイアウトを、CSSだけで実現する方法を書きました。

:::note warn
この記事を投稿している2022年8月17日現在、基本的にすべてのブラウザで利用不可です。
そのため、これは未来に向けた記事投稿です。
なお、Firefoxのみ`about:config`から`layout.css.grid-template-masonry-value.enabled`にすることで試すことができます。
:::

## 基本的な書き方

以下のようなHTMLに対してスタイルを当てる前提で進めます。

```html
<div class="grid">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>
```

まず、Masonryを適用したい領域に`display: grid;`を適用します。

```css
  .grid {
    display: grid;
  }
```

次に、`grid-template-columns`または`grid-template-rows`のどちらかに`masonry`を指定します。
`grid-template-columns`であれば水平方向の、`grid-template-rows`であれば垂直方向の空白を埋めるようにして配置されます。
以下の例では（使う頻度の多いであろう）`grid-template-rows`を採用しました。

```diff
  .grid {
    display: grid;
+   grid-template-rows: masonry;
  }
```

最も簡単な書き方で言えば、上記で完了です。
あとは`gap`や`background-color`など、見た目を整えるためのコードを追加するのみです。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="PoRLqpg" data-user="xrxoxcxox" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/xrxoxcxox/pen/PoRLqpg">
  Untitled</a> by Keisuke Watanuki (<a href="https://codepen.io/xrxoxcxox">@xrxoxcxox</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## 配置の仕組み

実態は[詳細なアルゴリズム](https://drafts.csswg.org/css-grid-3/#masonry-layout-algorithm)によって決定されるのですが、人間がざっくり理解するための説明を記載します。

ずばり「最も余白のある列（または行）に次々と要素を配置する」です。

先ほどのCodePenでの例をもとに説明します。
まず、1番目の要素を配置する際は、まだ1つも要素がないので通常のCSS Gridと同じ仕組みで配置されます。
今回で言えば左上です。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/8c2c26b5-3377-ffe3-5261-9c59e11ca008.png)

次に、2から4番目の要素です。
例では`grid-template-columns: repeat(4, 1fr);`という指定をしているため、4列描画されることは確定です。
そのため4番目までの要素は左から順に詰めて配置されます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/687ce126-1319-9395-cbbc-2ffb9986d7b3.png)

5番目の要素を配置します。
1から4列目を見ると、最も余白が大きいのは1列目です。
そのため、5番目の要素は1列目に配置されます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/c9020be0-3111-242f-08d7-371718f40a4a.png)

5番目の要素の配置により、最も余白が大きいのは3列目となりました。
そのため6番目の要素は3列目に配置されます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/e70a1e81-4978-ed06-4c1e-f272b0cdd8af.png)

6番目の要素を配置してもなお、最も余白が大きいのは3列目です。
そのため、7番目の要素も3列目に配置されます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/5e298c7f-22cd-8bd9-7b2c-0165c8fb573b.png)

残りの、8から10番目の要素は、ここまでの流れに沿って配置されるのみです。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/0e39791a-a600-2a9c-aa7c-9d7c30949d48.png)

ときには「あくまでHTMLの記載順通りに配置して欲しい」と思うかもしれません。
その場合は`masonry-auto-flow: next;`を指定すると良いでしょう。
こちらを指定すると、あくまでグリッド順に沿って順番に要素が配置されるようになります。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/4b9d70b4-bf86-6d58-c521-894a80bb2598.png)

## 応用的な書き方

先ほどの例でいうと、`.item`クラスのついた要素に`grid-column-start: span 2;`などを指定し幅を変えたり、`grid-column: 2 / 4;`などを指定して位置を固定したりもできます。

通常の`display: grid;`と同様に、明確な配置指定をもつ要素はそうでない要素よりも優先的に配置されるので、先ほど説明した流れからは少し変わります。

また、`align-content`のような役割を果たす`align-tracks`と`justify-tracks`というプロパティも存在します。
取りうる値も`align-content`と同じなのですが、カンマ区切りで複数指定して、それぞれの列（または行）に個別で設定が可能です。

## 参考

- https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout
- https://drafts.csswg.org/css-grid-3/

---

最後まで読んでくださってありがとうございます！
Twitterでも情報を発信しているので、良かったらフォローお願いします！

https://twitter.com/xrxoxcxox