~/home of geeks

HUGO responsive Bilder

· 693 Wörter · 4 Minute(n) Lesedauer

Bilder werden im Webseiten-Framework Hugo per Markdown definiert. Die Default-Ausspielung generiert ein einfaches Img-Tag mit dem hinterlegten Bild. Für dieses Blog habe ich ein Template entwickelt, welches verschiedene Bildauflösungen für verschiedene Geräte-Auflösungen generiert (responsive images).

Responsive Bilder #

Responsive Images sind Bilder, die sich an die Auflösung des Gerätes anpassen. Die einfachste Implementierung ist das HTML-Picture-Element, das eine Liste von Bildern für verschiedene Auflösungen bereitstellt. Der Browser wählt dann das passende Bild aus.

Das sieht üblicherweise wie folgt aus:

<picture>
    <source media="(min-width: 450px)" srcset="img_500.jpg" />
    <source media="(min-width: 650px)" srcset="img_700.jpg" />
    <img src="img_100.jpg" />
</picture>

Über die Source-Elemente werden die verschiedenen Auflösungen aufgelistet und über Media-Queries, wie (min-width: 450px), wird die Auflösung des Gerätes abgefragt und das passende Bild ausgewählt. Das 500-Pixel breite Bild benötigt eine Auflösung von mindestens 450 Pixeln, damit es nicht aus dem Sichtbereich des Gerätes herausragt.

Das Img-Tag wird als Fallback verwendet, wenn der Browser kein Picture-Element unterstützt oder die Auflösung kleiner ist als das kleinste Source-Element.

Hugo #

In Hugo werden Bilder über Markdown definiert. Das sieht wie folgt aus:

![Bildbeschreibung](/images/bild.jpg)

Die Default-Ausspielung von Hugo generiert ein Img-Tag:

<img src="/images/bild.jpg" alt="Bildbeschreibung" title="Bildbeschreibung">

Glücklicherweise kann man die Ausspielung des Bildes über ein Template steuern. Das Template muss hierzu als layouts/_default/_markup/render-image.html abgelegt werden.

Bilder können in Hugo an zwei Stellen abgelegt werden: Als Page-Resources oder als Static-Resources.

Bei Page-Resourcen wird pro Post / Page ein Ordner unter posts angelegt und dort können die Bilder zusammen mit einer index.md abgelegt werden. Die Bilder werden dann über den relativen Pfad images/bild.jpg referenziert. Ich setze dieses Schema nicht ein.

Statische Resourcen liegen normalerweise unter static/images und werden analog über images/bild.jpg referenziert. Für unsere Zwecke müssen wir die Bilder aber unter assets/images ablegen, da wir so aus Hugo heraus beliebige Auflösungen generieren können.

Fallbacks, Resourcenauswahl und Bildgrößen #

Damit beide Arten von Bildern unterstützt werden, muss das Template die Bilder anhand des relativen Pfades suchen. Hierzu wird das Bild zuerst als Page-Resource über .Page.Resources.Get geladen. Wenn das Bild nicht gefunden wird, wird es über die statischen Resourcen via resources.Get geladen. Für den Fall, dass das Bild nicht gefunden wird, wird im Voraus ein statisches Fallback-Bild definiert. Dem Template selbst wird das aktuelle Bild-Objekt übergeben.

{{ $originalImage := resources.Get "images/glider.png" }}
{{ with .Destination }}
    {{ with $.Page.Resources.Get . }}
        {{ $originalImage = . }}
    {{ else }}
        {{ with resources.Get . }}
            {{ $originalImage = . }}
        {{ end }}
    {{ end }}
{{ end }}

Anschließend wird ermittelt, welche Größe das Originalbild hat. Denn alle größeren Formate sollten wir nicht generieren, das sieht nicht gut aus.

Template #

<!-- Fallback-Bild definieren, dass dann auch klein ist -->
{{ $originalImage := resources.Get "images/glider.png" }}
{{ $myTitle := i18n "image not found" }}
{{ with .Destination }}
    {{ $myTitle := $.Title }}
    <!-- Page-Resources -->
    {{ with $.Page.Resources.Get . }}
        {{ $originalImage = . }}
    {{ else }}
        <!-- Static-Resources -->
        {{ with resources.Get . }}
            {{ $originalImage = . }}
        {{ end }}
    {{ end }}
{{ end }}

<p class="md-image">
    <picture>
<!-- Größen anhand der Originalgröße bestimmen -->
{{ $width := $originalImage.Width }}

{{ if gt $width 800 }}
    {{ with $originalImage.Resize "800x" }}
        <source media="(min-width:800px)" srcset="{{ .RelPermalink | safeURL }}" />
    {{ end}}
{{ end }}

{{ if gt $width 1200 }}
    {{ with $originalImage.Resize "1200x" }}
        <source media="(min-width:1200px)" srcset="{{ .RelPermalink | safeURL }}" />
    {{ end}}
{{ end }}

{{ if gt $width 1500 }}
    {{ with $originalImage.Resize "1500x" }}
        <source media="(min-width:1500px)" srcset="{{ .RelPermalink | safeURL }}" />
    {{ end}}
{{ end }}

{{ if gt $width 2200 }}
    {{ with $originalImage.Resize "2200x" }}
        <source media="(min-width:2200px)" srcset="{{ .RelPermalink | safeURL }}" />
    {{ end}}
{{ end }}

{{ $tinyImage := $originalImage }}
{{ if gt $width 500 }}
    {{ $tinyImage = $originalImage.Resize "500x" }}
{{ end }}
        <img src="{{ $tinyImage.RelPermalink | safeURL }}" alt="{{ $myTitle }}" title="{{ $myTitle }}" />
    </picture>
</p>