I was converting a website from WordPress to Hugo and needed an equivalent to the Tiled Image Gallery from Wordpress. I wanted the Tiled Mosaic style, but that was a little to complex, as it also contains colspans. I came up with this as an alternative.
Demo and code can be found on Codepen
It has a WTFPL license and is almost fully ‘vibe coded’. It is Javascript-heavy and requires no CSS. It uses a simple HTML structure, as illustrated below:
<div class="gallery">
<a href="full_img_src">
<img ratio="0.666" src="thumb_img_src" />
</a>
...
</div>
The hardest part of using this code is determining the image ratio before rendering. Any server side language (like PHP) can generate these image ratios though, as can Hugo (which I have built this for). Knowing the image ratio before loading the images prevents layout shifts and ensures a smooth loading experience.
This whole javascript is only a few kilobytes large, so it loads relatively quickly. It is fully responsive and has a debounce function that limits the redraws to 50ms, preventing it from being CPU-heavy.
Aestheticly, it aims for about 1 image every 700px of width. The images always fill out nicely and the code prevents subpixel issues. Images have a minimum size, which turns the gallery into a list of images on mobile. The margin between the images is 4px.
I did not take the time to fully understand the code, but it works pretty nice. The Hugo code I used is:
{{- if in .Params.thumbnail_image “/uploads/gallery” -}}
{{- $dir := (path.Dir .Params.thumbnail_image) -}}
{{- range (readDir (print "/static" $dir)) -}}
{{- $resource := resources.Get (printf "%s/%s" $dir .Name) -}}
{{- $thumb := $resource.Resize "600x" -}}
{{- $thumburl := $thumb.RelPermalink -}}
{{- $imageurl := printf "%s/%s" $dir .Name -}}
{{- $imagetitle := index (split .Name ".") 0 -}}
{{- $ratio := div (float $thumb.Width) (float $thumb.Height) -}}
<a href="{{ $imageurl }}">
<img data-ratio="{{ $ratio }}" src="{{ $thumburl }}" alt="{{ $imagetitle }}" loading="lazy">
</a>
{{- end -}}
{{- end -}}
Note that this code plays well with the Lightbox on Hugo Codex:
Enjoy!