Problem: figures in hugo should nicely align in text and open in a lightbox
Solution: hugo
, lightbox
, jquery
Note, that the test images used in this post are from the MNIST database and one of Lena Forsén taken from Wikipedia and is photographed by Dwight Hooker for the Playboy Magazine.
Examples
Adding a single image with plain markdown and no formatting:
![Lena Forsén](lenna-test-image-100-100.png)
Adding an image with HTML, embedded in markdown:
<img src="mnist-3-a.png" alt="A sample digit from the MNIST database." />
This version allows you to specify more custom markup. I am using a CSS class floatright which allows me to easily embed images as floating blocks within my content.
The figure shortcode is often styled based on your used Hugo theme and provides prettified integration into your posts. It also allows a caption-attribute for attaching a note directly to the image. Often I simply combine it with custom CSS. As the caption might increase the width of your figure environment and your image might be smaller (as in the case with this image of a seven), you might need to force the environment to a reduced width – although I usually dislike formatting such sizes directly, because layout might change.
{{< figure src="mnist-7-a.png" class="floatright" width="20%" caption="A sample digit from the MNIST database." >}}
I actually extended the figure shortcode and integrated a data-lightbox attribute to the contained anchor. Furthermore, I added jquery and lightbox to the site. This makes it possible to directly add lightbox-functionality to every figure I am using (check it out by clicking on it).
{{< figure class="floatright" src="lenna-test-image-512-512.png" caption="A scanned photograph of Lena Forsén, floating right." >}}
To further put multiple figures into a group and provide a gallery-like lightbox experience, one can specify a value for the lightbox-attribute. As soon as the lightbox opens, one can navigate through the images with navigation keys or via clicks.
<div class="multi-figures">
{{< figure src="mnist-0-a.png" lightbox="mnist-samples" width="6%" >}}
{{< figure src="mnist-1-a.png" lightbox="mnist-samples" width="6%" >}}
{{< figure src="mnist-2-a.png" lightbox="mnist-samples" width="6%" >}}
{{< figure src="mnist-3-a.png" lightbox="mnist-samples" width="6%" >}}
{{< figure src="mnist-4-a.png" lightbox="mnist-samples" width="6%" >}}
{{< figure src="mnist-5-a.png" lightbox="mnist-samples" width="6%" >}}
{{< figure src="mnist-6-a.png" lightbox="mnist-samples" width="6%" >}}
{{< figure src="mnist-7-a.png" lightbox="mnist-samples" width="6%" >}}
{{< figure src="mnist-8-a.png" lightbox="mnist-samples" width="6%" >}}
{{< figure src="mnist-9-a.png" lightbox="mnist-samples" width="6%" >}}
<figcaption class="img--caption">
Samples for each labeled class in the MNIST database.
You can click through a lightbox-gallery as they have the same attribute attached.
</figcaption>
</div>
Integrating lightbox in Hugo
Lightbox is one of the first javascript-libraries easily adding functionality to your images, opening them temporarily in an overlay box over your content.
Steps to integrate the lightbox library in Hugo:
- download lightbox from the github release page.
- add jQuery and lightbox javascript files to the footer of your page
- add lightbox css files to the head of your page
- add/overwrite a custom shortcode, e.g. figure, to integrate images with the lightbox-specific attribute
Adding javascript & css files
I extended the hyde-hyde Hugo theme to easily add custom CSS/javascript to the header/footer.
Copy the lightbox css file (the minified version at best) e.g. from /lightbox2-2.11.1/dist/css/lightbox.min.css into your Hugo repository at /static/css/.
You then only have to add it to the <head>
-section of your theme:
<link rel="stylesheet" href="/css/lightbox.min.css">
Copy the lightbox javascript file e.g. from /lightbox2-2.11.1/dist/js/lightbox.min.js into your Hugo repository at /static/js/.
The javascript code is then integrated at the end of your <body>
-part of the theme:
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="/js/lightbox.min.js"></script>
You then also need to make sure, that you add static images to your css relative to /css/lightbox.min.css into a ../images/-folder, thus into /static/images/close.png (and the other images used in lightbox).
(Thanks to Mark Barrett noticing a copy-paste error in the previous html snippet)
Using a shortcode to add lightbox
I added a custom shortcode to /layouts/shortcodes/figure.html (see below).
This shortcode wraps HTML images with a figure-tag (which is usually already formatted by your theme) and puts an anchor around them.
The anchor uses the path of your image as a keyword for lightbox, added to the attribute data-lightbox.
This keyword can also be manually defined by setting a custom name, e.g. {{<figure lightbox="abc" .. >}}
.
Figures with the same lightbox keyword are combined in gallery-style (see the lightbox reference).
{{ if .Get "caption" }}
{{ $.Scratch.Set "caption" (.Get "caption") }}
{{ else if .Get "alt" }}
{{ $.Scratch.Set "caption" (.Get "alt") }}
{{ end }}
<!-- resolve absolute image path -->
{{ $permalink := $.Page.Permalink }}
{{ $image := .Get "src" }}
{{ $image_link_absolute := (findRE "^/" $image) }}
<figure
{{ with .Get "class" }}class="{{.}}"{{ end }}
{{ with .Get "width" }}style="width: {{ . }};"{{ end }}
{{ with .Get "height" }}style="height: {{ . }};"{{ end }}
>
<a
{{ if .Get "lightbox" }}
data-lightbox="{{ .Get "lightbox" | markdownify | plainify }}"
{{ else }}
data-lightbox="image-{{ $image }}"
{{ end }}
{{ if $image_link_absolute }}
href="{{ $image | absURL }}"
{{ else }}
href="{{ (printf "%s%s" $permalink $image) }}"
{{ end }}
{{ with .Get "target" }} target="{{ . }}"{{ end }}
{{ with .Get "rel" }} rel="{{ . }}"{{ end }}>
<img
{{ if $image_link_absolute }}
src="{{ $image | absURL }}"
{{ else }}
src="{{ (printf "%s%s" $permalink $image) }}"
{{ end }}
{{ if .Get "alt" }}alt="{{ .Get "alt" | markdownify | plainify }}"
{{ else if .Get "caption" }}alt="{{ .Get "caption" | markdownify | plainify }}"
{{ end }}
{{ with .Get "align" }}align="{{ . }}"{{ end }}
/>
</a>
<!-- caption and attr-->
{{ if ($.Scratch.Get "caption") }}
<figcaption>
<span class="img--caption">
Figure {{ $.Page.Scratch.Get "fig" }}. {{ $.Scratch.Get "caption" | markdownify | plainify }}
{{ if .Get "attr" }}
[{{- with .Get "attrlink"}}<a href="{{ . }}">{{ end }}{{ .Get "attr" | markdownify }}{{ if .Get "attrlink"}}</a>{{ end -}}]
{{ end }}
</span>
</figcaption>
{{ end }}
</figure>
{{ .Page.Scratch.Add "fig" 1 }}
{{ $.Scratch.Delete "caption"}}