18.2.2023

Masonry Layout and AstroJS

Recently, I have re-implemented my blog with Astro. They have just released version 2.0 of Astro with some compelling features and since my previous solution (gridsome) has not been updated for years now, I decided to give Astro a chance. I sticked with most of my layout and structure, but had to change image handling.

One challenge was how to integrate a masonry layout for my blog and theater pages. Therefore I needed to find a way to do this with

Luckily, this case is documented on the Bootstrap page on cards. They provide an example on how to integrate it, which served me as a starting point.

Base Layout

First step is to install the required dependencies.

> npm install bootstrap
> npm install masonry-layout
> npm install imagesLoaded

You need to include the JS dependencies in your main layout.

---
import bootstrap from "bootstrap/dist/js/bootstrap.bundle.min?url";
import masonry from "masonry-layout/dist/masonry.pkgd.min?url";
import imagesLoaded from "imagesloaded/imagesloaded.pkgd.min?url";
---

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" type="image/png" href="/img/favicon.png" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="generator" content="{Astro.generator}" />
  </head>
  <body>
    ...
    <script src="{bootstrap}"></script>
    <script src="{imagesLoaded}"></script>
    <script src="{masonry}"></script>
  </body>
</html>

Include Masonry

Since I use images on my pages, I also needed to include the imagesLoaded library to update the layout after all images have been loaded. So my way of masonry initialization is bundled in one JavaScript file.

var $grid = document.querySelector(".grid");
imagesLoaded($grid, function () {
  new Masonry(".grid", {
    percentPosition: true,
  });
});

This file can be included wherever a masonry layout is needed. Just add the following snippet at the end of your page.

<script>import "@scripts/masonry.js";</script>

This requires a path for @scripts to be present in tsconfig.json.

Markup

Finally add the markup as suggested by bootstrap in the blog overview page.

<div class="grid row mt-4">
  { allPosts.map((post) => (
  <div class="col-md-6 col-lg-4 mb-4">
    <BlogPost url="{post.slug}" frontmatter="{post.data}" />
  </div>
  )) }
</div>

Since I use .grid as hook for masonry, this CSS class is there together with Bootstrap’s .row. This should do the trick.