Ein paar Informationen dazu, wie man in Hugo Bilder einbinden kann, welche Hilfsmittel es gibt und auch, was mit Bordmitteln von Hugo nicht möglich ist. Und zum Schluss ein eigener Render-Hook, der hilfreiche Dinge macht.

Update

Update 1 (27.04.2022): Im Blog wird jetzt ein aktuelleres und verbessertes Render Hook verwendet, siehe hier.

Update 2 (04.04.2023): Es gibt wieder einen verbesserten Render Hook, der sich am Ursprungsformat eines Fotos orientiert, nur auf Webp für die Bildvarianten ausgelegt ist und somit sehr viel schneller ist und viel weniger Daten produziert, siehe hier.

Bilder in Hugo

Es gibt verschiedene Möglichkeiten zur Einbindung von Bildern in Hugo.

Standard-Markdown-Syntax – Tut, kann aber nix

Die Standard-Markdown-Syntax, die Hugo von sich aus unterstützt, funktioniert zwar, kann dafür aber nichts:

![Alt Text](/pfad/zu-datei.jpg)

Das bedeutet konkret:

  • Keine Möglichkeit zur Angabe, wie groß das Bild dargestellt wird, es wird immer maximal groß angezeigt.
  • Es werden keine kleineren Bildvarianten erstellt. Ist ein Bild z. B. 10 MiB groß, 2000 Pixel breit und beträgt der zur Verfügung stehende Platz im Blog nur 800 Pixel in der Breite, so wird trotzdem das Originalbild mit 2000 Pixeln eingebunden, nur eben verkleinert und man muss 10 MiB herunterladen.

Render Hook

Für einen Render Hook erstellt man die Datei layouts/_default/_markup/render-image.html.

Hier kann man Programmcode hinterlegen, der ausgeführt wird, sobald die Standard-Markdown-Syntax für die Einbindung von Bildern gerendert wird.

Dies hat den Vorteil, dass man im Gegensatz zu einem Shortcode beim Standard-Markdown bleiben oder diesen auch erweitern kann.

Theme-Erweiterungen

Das hier im Blog verwendete Theme ‘Bootstrap’ stellt einige Möglichkeiten zum Einbinden von Bildern bereit. So kann man z. B. Bilder verkleinert anzeigen lassen und dafür wird auch wirklich eine kleinere Variante des Originalbildes erzeugt (wenn das Bild Teil des Page Bundles ist).

Es kann eine erweitere Standard-Markdown-Syntax verwendet werden, wie z. B.

![Alt Text](pfad/zu-datei.jpg?height=200px)

Letztlich wird das üer einen Render Hook ermöglicht, siehe oben.

Shortcode

Es gibt im Netz verschiedene Lösungen in Form von Shortcodes, die z. B. automatisch kleinere Varianten der Bilder erstellen und diese einbinden statt des Originals und es auch ermöglichen, einen Link auf das Originalbild zu setzen, einen Text unter dem Bild anzuzeigen und mehr.

Solch einen Shortcode hatte ich bis vor kurzem auch verwendet. Jedoch muss man für Shortcodes eine andere Syntax verwenden, z. B. für den Shortcode bildeinbinden:

{{​< bildeinbinden src="" link="" alt="" title="" width="" >​}}

So nah am Standard, wie möglich

Ich bevorzuge die Verwendung von gegebenen Standards statt einer eigenen Lösung. Denn so werden Probleme beim Wechsel eines Themes oder auch beim Export minimiert.

So verwende ich lieber die Standard-Markdown-Syntax für das Einbinden von Bildern in Hugo statt eines eigenen Shortcodes, dessen Parameter man sich mehr oder weniger merken muss. Zudem ist es für neue Menschen leichter.

Deshalb habe ich mich hier im Blog für einen Render Hook entschieden, um Bilder einzubinden.

Der eigene Render Hook

Als Ausgangspunkt habe ich diese Version hier verwendet und für meine Anforderungen angepasst.

Die Syntax ist die selbe wie in Hugo:

![Alt-Text](bild-200px.jpg "Titel")

z. B.

![Ein Demobild mit Radfahrenden, um zu verdeutlichen, wie ein Bild mit dem eigenen Render Hook eingebunden wird. ](bild-200px.jpg "Radfahrende in Pforzheim")

Im Ergebnis das 200 Pixel breite Bild, das nicht automatisch verlinkt wird, weil es zu klein ist:

Ein Demobild mit Radfahrenden, um zu verdeutlichen, wie ein Bild mit dem eigenen Render Hook eingebunden wird.
Radfahrende in Pforzheim

Und hier ein Beispiel eines Bildes, das 2000 Pixel breit ist und deshalb automatisch zum Originalbild verlinkt, während automatisch eine erzeugte kleinere Variante (800 Pixel breit) des Originalbildes hier eingebunden wird.

Aus:

![Fahrrad auf einem Feldweg und mit einem 'Vorsicht Kinder' Schild auf dem Gepäckträger](bild-gross.jpg "Das Schild habe ich zuvor am Straßenrand gefunden.")

Wird:

Fahrrad auf einem Feldweg und mit einem &lsquo;Vorsicht Kinder&rsquo; Schild auf dem Gepäckträger
Das Schild habe ich zuvor am Straßenrand gefunden.

Man kann jedoch sowohl den Alt-Text als auch den Titel weglassen.

Hinweis

Mir gefällt jedoch an dieser Syntax, dass man immer daran erinnert wird, einen Beschreibungstext zu hinterlegen und nicht nur einen Titel. Denn der Beschreibungstext (Alt-Text) ist wichtig für Menschen mit Sehbeeinträchtigungen.

Ich werde in Zukunft somit darauf achten, solche Texte zu hinterlegen. In der Vergangenheit habe ich das im Blog fast nie getan.

Quelltext

Hier der fertige Render Hook layouts/_default/_markup/render-image.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{{ $autolinking := .Page.Param "imageAutoLink" | default true }}
{{- $img := .Page.Resources.GetMatch .Destination -}}
{{- if and (not $img) .Page.File -}}
{{ $path := path.Join .Page.File.Dir .Destination }}
{{- $img = resources.Get $path -}}
{{- end -}}
{{- with $img -}}
{{- $large := $img.Resize "816x" -}}
{{- $medium := $img.Resize "500x" -}}
{{- $small := $img.Resize "360x" -}}
<figure class="image-caption">
{{ if gt $img.Width 816 }}
	{{ if and (gt $img.Width 1000) (eq $autolinking true ) }}<a href="{{- $img.RelPermalink -}}">{{ end }}
    <img alt="{{ $.Text }}" srcset="
        {{ $small.RelPermalink }} 360w,
        {{ $medium.RelPermalink }} 500w,
        {{ $large.RelPermalink }} 816w" sizes="(max-width: 424px) 360px,(max-width: 596px) 500px,(min-width: 565px) 816px" src="{{ $small.RelPermalink }}" title="{{ $.Title }}" loading="lazy" />
    {{ if and (gt $img.Width 1000) (eq $autolinking true ) }}</a>{{ end }}
{{ else }}
    <img alt="{{ $.Text }}" src="{{ $img.RelPermalink }}" loading="lazy" title="{{ $.Title }}" />
{{ end }}
    <figcaption>{{ with $.Title | safeHTML }}{{ . }}{{ end }}</figcaption>
</figure>
{{- else -}}
<img src="{{ .Destination | safeURL }}" alt="{{ $.Text }}" title="{{ $.Title }}" loading="lazy" />{{- end -}}
<!-- adapted from https://github.com/bep/portable-hugo-links/blob/master/layouts/_default/_markup/render-image.html -->

Wie der neue Render Hook funktioniert

Und so funktioniert der neu erstellte Render Hook render-image.html:

  • Bild ist breiter als 816 Pixel1:
    • Es werden automatisch kleinere Bildvarianten erstellt und via srcset eingebunden.
  • Bild ist schmaler als 816 Pixel:
    • Es werden keine kleineren/größeren Bildvarianten erstellt und auf ein srcset wird verzichtet, es wird nur das Originalbild eingebunden. (Man könnte noch implementieren, dass in letzterem Fall nur die Bildvarianten erstellt werden, die kleiner als 816 Pixel sind. Aber das spare ich mir, da das nur selten vorkommt und das meistens Dateien mit sehr geringen Dateigrößen sind.)
    • Hierdurch wird ein sehr kleines Bild wirklich nur so groß angezeigt, wie es auch ist, nicht vergrößert und matschig.
  • Bild ist breiter als 1000 Pixel:
    • Es wird automatisch ein Link auf das Originalbild gesetzt. Das Verlinken kann man unterbinden mit imageAutoLink: false im Front Matter eines Blogbeitrags.
  • Der angegebene Titel wird unter dem Bild angezeigt.
  • Der angegebene Alt-Text in eckigen Klammern wird in das alt-Attribut eingefügt.
  • Die Bilder werden per Lazy loading eingebunden, sodass der Browser sie erst herunterlädt, wenn sie in der Nähe des Sichtbereits im Browser sind. Das spart Ressourcen, falls man nur einen Teil eines Beitrags liest.
  • Es werden kleine Bildvarianten mit 500 und 360 Pixeln Breite erstellt. Diese sind für die kleineren Ansichten im Blog notwendig, z. B. auf Mobilgeräten.

Ideen für später

  • Es wäre schön, wenn die Beschreibung aus den Exif-Tags verwendet werden könnte, sofern man keine eigene Beschreibung in Markdown einträgt. Ein Beispiel einer Umsetzung gibt es hier.
  • Angabe von selbst festgelegter Breite für das Einbinden eines Bildes, wie z. B. hier beschrieben oder auch im hier im Blog verwendeten Theme.

Uffbasse (Aufpassen) – Besser kein srcset bei kleinen Bildern

Man kann Hugo anweisen, kleinere Bildvarianten des Originalbildes zu erstellen, die man dann statt des Originalbildes verwenden kann. Alternativ kann man daraus ein srcset erstellen, sodass der Browser automatisch die passende Größe aussuchen und herunterladen kann.

Jedoch ist dieser Mechanismus der Erstellung von Bildvarianten in Hugo ziemlich “dumm”. Wenn z. B. das Bild nur 200 Pixel breit ist, werden angeforderte größere Bildvarianten trotzdem erstellt und das resultiert dann in einem total zermatschten größeren Bild.

In diesem Screenshot wird das deutlich sichtbar. Das Originalbild (200 Pixel breit) und darunter das Bild, das von Hugo auf Anfrage in 800 Pixel Breite erzeugt wurde, obwohl das Originalbild kleiner ist:

Oben das Originalbild in 200 Pixel breite und darunter das von Hugo angefragte aus dem Originalbild erzeugte Bild mit circa 800 Pixeln, das entsprechend breit angezeigt wird und natürlich total zermatscht ist.
Oben das Originalbild in 200 Pixel breite und darunter das von Hugo angefragte aus dem Originalbild erzeugte Bild mit circa 800 Pixeln, das entsprechend breit angezeigt wird und natürlich total zermatscht ist.

Jedoch kann man in Hugo per .Width die Breite eines Bildes abfragen und nur dann weitere Bildvarianten erstellen lassen, wenn eine Mindestbreite gegeben ist und bei zu kleinen Bildern auf srcset verzichten.

Passt

Ich bin mit der neuen Lösung erst einmal zufrieden. Ich kann die Standard-Markdown-Syntax verwenden, es wird automatisch ein srcset eingefügt und große Bilder werden automatisch zum Originalbild verlinkt. Und zusätzlich werde ich auch noch daran erinnert, einen passenden Alt-Text zu schreiben.


  1. 816 Pixel ist die Breite des Inhalts in der Standardansicht meines Blog. ↩︎