-
-
Save cpbotha/deb310eed14308fe26f7b7d0fabeb34d to your computer and use it in GitHub Desktop.
{{/* | |
figure with auto-resizing and srcset v2024-11-24 | |
Drop-in replacement for Hugo's figure shortcode which uses img srcset | |
to enable browsers to download only the resolution that they need. | |
The resizing and srcset magic only works for images that are part of the page | |
bundle. It will fall back to stock Hugo figure behaviour otherwise. | |
Improvements that were initially out of reach of my Hugo template programming "skills" | |
but have now been taken care of: | |
- [x] gracefully handle images that are not in page bundle, i.e. no image processing available | |
- [x] use a single configurable sizes array, and derive everything from there | |
See https://cpbotha.net/2020/05/02/drop-in-replacement-for-hugo-figure-shortcode-with-img-srcset-support/ | |
- original srcset img shortcode from: https://laurakalbag.com/processing-responsive-images-with-hugo/ | |
- original hugo figure shortcode from: https://github.com/gohugoio/hugo/blob/master/tpl/tplimpl/embedded/templates/shortcodes/figure.html | |
- no unnecessary resizes and more nudges by Stéfan van der Walt https://mentat.za.net/ | |
- mashing together and srcset logic fixes by Charl P. Botha https://cpbotha.net/ | |
Changes: | |
- 2024-11-24 work-around for bug in golang where it breaks webp images during resizing. Please add png or jpg version of your webp. | |
- 2020-05-10 fall back to stock Hugo behaviour when no page bundle found | |
- 2020-05-04 no unnecessary resizes, sizes in array | |
- 2020-05-02 initial release | |
*/}} | |
{{/* hugo will resize to all of these sizes that are smaller than your original. configure if you like! */}} | |
{{ $sizes := (slice "480" "800" "1200" "1500") }} | |
{{/* get file that matches the filename as specified as src="" in shortcode */}} | |
{{ $src := .Page.Resources.GetMatch (printf "*%s*" (.Get "src")) }} | |
{{/* work-around for bug in golang where webp images are degraded during decoding / processing: | |
https://github.com/golang/go/issues/40173 | |
in short: use .webp as src, but also add a png or jpg version. This code will link webp files everywhere, | |
but it will use the jpg/png as the image processing source */}} | |
{{ $srcIP := $src }} | |
{{ if and $src (strings.HasSuffix $src.Name ".webp") }} | |
{{/* use .jpg if that exists, else .png */}} | |
{{ $srcPNG := .Page.Resources.GetMatch (printf "*%s*" (replace (.Get "src") ".webp" ".png")) }} | |
{{ $srcJPG := .Page.Resources.GetMatch (printf "*%s*" (replace (.Get "src") ".webp" ".jpg")) }} | |
{{ if $srcPNG }} | |
{{ $srcIP = $srcPNG }} | |
{{ else if $srcJPG }} | |
{{ $srcIP = $srcJPG }} | |
{{ end }} | |
{{ end }} | |
<figure{{ with .Get "class" }} class="{{ . }}"{{ end }}> | |
{{- if .Get "link" -}} | |
<a href="{{ .Get "link" }}"{{ with .Get "target" }} target="{{ . }}"{{ end }}{{ with .Get "rel" }} rel="{{ . }}"{{ end }}> | |
{{- end }} | |
<img | |
{{ if $src }} | |
sizes="(min-width: 35em) 1200px, 100vw" | |
{{/* only srcset images smaller than or equal to the src (original) image size, as Hugo will upscale small images */}} | |
srcset=' | |
{{ range $sizes }} | |
{{/* explicit MediaType.SubType to support our webp work-around without affecting non-webp use */}} | |
{{ if ge $src.Width . }}{{ ($srcIP.Resize (printf "%sx %s" . $src.MediaType.SubType)).Permalink }} {{ (printf "%sw" .) }},{{ end }} | |
{{ end }}' | |
{{/* when no support for srcset (old browsers, RSS), we load small (800px) */}} | |
{{/* if image smaller than 800, then load the image itself */}} | |
{{ if ge $src.Width "800" }}src="{{ ($srcIP.Resize (printf "800x %s" $src.MediaType.SubType)).Permalink }}" | |
{{ else }}src="{{ $src.Permalink }}" | |
{{ end }} | |
{{ else }} | |
{{/* fall back to stock hugo behaviour when image is not available in bundle */}} | |
src="{{ .Get "src" }}" | |
{{ end }} | |
{{- if or (.Get "alt") (.Get "caption") }} | |
alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "caption" | markdownify| plainify }}{{ end }}" | |
{{- end -}} | |
{{- with .Get "width" }} width="{{ . }}"{{ end -}} | |
{{- with .Get "height" }} height="{{ . }}"{{ end -}} | |
/> <!-- Closing img tag --> | |
{{- if .Get "link" }}</a>{{ end -}} | |
{{- if or (or (.Get "title") (.Get "caption")) (.Get "attr") -}} | |
<figcaption> | |
{{ with (.Get "title") -}} | |
<h4>{{ . }}</h4> | |
{{- end -}} | |
{{- if or (.Get "caption") (.Get "attr") -}}<p> | |
{{- .Get "caption" | markdownify -}} | |
{{- with .Get "attrlink" }} | |
<a href="{{ . }}"> | |
{{- end -}} | |
{{- .Get "attr" | markdownify -}} | |
{{- if .Get "attrlink" }}</a>{{ end }}</p> | |
{{- end }} | |
</figcaption> | |
{{- end }} | |
</figure> |
Very cool.
I've made some changes to handle the situation where:
- The image is an SVG
- The image needs to be rotated
I'm not great with git/github so see https://petersmith.org/blog/2023/01/19/figure-shortcode-again-/ for details
If you add the below on line #59 you will get a better pagespeed score with your images. Surprisingly, it only cares if the value is defined. Not that it matches the dimensions of the specific image being served.
width="{{ $src.Width }}"
height="{{ $src.Height }}"
I have just updated the shortcode to support working around this 4-year old webp decoding bug in the golang standard library: golang/go#40173
Here is more discussion on Hugo's github: gohugoio/hugo#8879
In short, the golang stdlib mangles webp images during decoding, which results in visible colour changes. I ran into this in a recent post with screenshots with white backgrounds, which turned into super grey.
With these changes in the shortcode, you can add e.g. "my_image.webp" and use that in the src
and link
attributes, but you must also add a "my_image.png" (or .png) version. The .png or .jpg will be used for all resizing, but your final page will link only the webp files.
Thanks for the note, and the thanks!
I did just double-check: Fortunately the comment right above that line fortunately describes the intent, and the code does follow that.