Creating a Pinterest-style image gallery with Quarto

How I used masonry.js via Quarto extensions to create a cascading grid layout for a set of images without any Javascript skills.

how-to
images
quarto
Author

Cynthia Huang

Published

July 23, 2024

Modified

August 13, 2024

Standard vs. Cascading Grid Layouts

I am a sucker for aesthetics and visual flow. In contests between function and form, I definitely lean towards form, though (hopefully) usually not at the expense of function. The upshot of this is that when I decided to share some sketches I made during my recent travels in Europe, I could not bring myself to just post them in a standard grid layout. It just didn’t look right. But lucky for the stubborn stylist in me, with a bit of Quarto extension magic, I managed to make a cascading layout instead.

See here for the actual gallery, complete with lightbox treatment for each of the images!1

Bridging my Taste > Skill mismatch with Quarto Extensions

With my very rudimentary front-end web development knowledge, I knew implementing the layout I wanted would involve some combination of HTML, CSS, Javascript type things. At first I didn’t even know what the layout was called, but a quick conversation in GitHub CoPilot about “Pinterest style image galleries” lead me to “Cascading Grid Layouts” and the masonry.js library.

Still, there was no way I was using said library with my beginner level web skills. Fortunately, @mcanouil has created an Quarto extension filter for using masonry.js in .qmd documents. The repo says it’s experimental, but it was the best option on offer for me. So, I went ahead and added the extension to my Quarto project:

quarto add mcanouil/quarto-masonry

Now all that was left was to look at the example.qmd, pull across the relevant divs and styles, and then tweak until I was satisified / got too hungry and had to go get tacos for dinner.

To use the installed extension, I needed to add the following to my Quarto document:

  • YAML option to use the extension via filters:
  • Additional CSS to define and select grid items via include-in-header:
  • Divs with the relevant grid item class containing the images we want to tile using ::: div fences.

Here is a a very simple document based on the example in mcanouil/quarto-masonry:

---
title: "My Cascading Gallery"
lightbox: true
filters:
  - masonry
include-in-header:
  - text: |
      <style>
        .grid-item {
          width: 200px;
          height: 160px;
          float: left;
          background: #D26;
          border: 2px solid #333;
          border-color: hsla(0, 0%, 0%, 0.5);
          border-radius: 5px;
        }
      <style>
---
:::: {.grid data-masonry='{ "itemSelector": ".grid-item", "gutter": 0 }'}
:::{.grid-item}
![example-caption-01](image-01.png)
:::
:::{.grid-item}
![example-caption-02](image-02.png)
:::
:::{.grid-item}
![example-caption-03](image-03.png)
:::
:::{.grid-item}
![example-caption-04](image-04.png)
:::
:::{.grid-item}
![example-caption-05](image-05.png)
:::
::::

The Tweaking Process

Getting everything working using the example was pretty easy, but I had to go through a few iterations of modifying CSS styles and inspecting the rendered page to:

  • change the tile size from fixed to flexible
  • change the tile background colour
  • hide the figure captions from the tiles, but retain the text for alt-text, hover-over and lightbox descriptions
  • remove the space between the bottom of the images and the bottom edge of the tiles

Screenshots of the tweaks

Fixed tile size and pink background

Flexibly sized white tiles, but ugly figure captions

No figure captions, but hanging margin underneath images in tiles

Here is an annotated version of the CSS I ended up using:

.grid-item {
    width: 25%;
    float: left;
    background: #FFFFFF;
    border: 2px solid #333;
    border-color: hsla(0, 0%, 0%, 0.5);
    border-radius: 5px;
}
figcaption {
    display: none;
}
.quarto-figure {
    margin-bottom: 0px;
    }
1
Not speficying height means the tiles expand with the image size
2
Controls the color of tile background
3
Controls display of text in <figcaption> element without affecting other attributes like alt-text
4
Modifies the margins of the .quarto-figure class add by Quarto when rendering inline image references

Bonus Automation with {glue}

I wrote in a previous blog post about using {glue} to generate layouts for collections of images programmatically. I adapted the idea to generate the grid items for the cascading layout instead of typing out each div and inline image reference by hand. Here’s a reference code snippet, in case you want to do the same. The double braces {{}} are used to escape the special characters {}.

img_files <- fs::dir_ls("images", glob="*.png")
img_captions <- paste0("example-caption-0", seq_along(img_files))
cat(glue::glue("
  :::{{.grid-item}}
  ![{img_captions}]({img_files}){{group='sketches'}}
  :::"),
  sep = "\n"
)
:::{.grid-item}
![example-caption-01](images/Screenshot_cascading-grid.png){group='sketches'}
:::
:::{.grid-item}
![example-caption-02](images/Screenshot_masonry-style-01.png){group='sketches'}
:::
:::{.grid-item}
![example-caption-03](images/Screenshot_masonry-style-02.png){group='sketches'}
:::
:::{.grid-item}
![example-caption-04](images/Screenshot_masonry-style-03.png){group='sketches'}
:::
:::{.grid-item}
![example-caption-05](images/Screenshot_std-grid.png){group='sketches'}
:::

Footnotes

  1. Lightbox figures have been available since Quarto v1.4. See docs here↩︎

Citation

BibTeX citation:
@online{huang2024,
  author = {Huang, Cynthia},
  title = {Creating a {Pinterest-style} Image Gallery with {Quarto}},
  date = {2024-07-23},
  url = {https://www.cynthiahqy.com/posts/masonry-gallery/},
  langid = {en}
}
For attribution, please cite this work as:
Huang, Cynthia. 2024. “Creating a Pinterest-Style Image Gallery with Quarto.” July 23, 2024. https://www.cynthiahqy.com/posts/masonry-gallery/.