Diese Internetzseite ist optimiert für die Betrachtung mit offener Developer-Console des Browsers.

Die Seite richtet sich an Webentwickler, daher verzichte ich darauf, den jederzeit ansehbaren HTML/JavaScript Code weiter zu dokumentieren. Wer wissen will, die das gerenderte Markup aussieht, dem sei der Seitenquelltext und die Developer-Console des Browsers empfohlen. Damit lässt sich noch viel mehr nachvollziehen. z.B.:

  • Ladezeiten
  • bei welchen Bildschirmgrössen werden welche Bilder geladen
  • wie gross sind die geladenen Bilder
  • durch Limitierung der Bandbreite des Browsers lässt sich der Effekt von Page-Reflows gut zeigen, da die Bilder damit verzögert laden

About

Um was gehts?

Hier zeige ich verschiedene Methoden, um innerhalb von TYPO3 adaptive images zu verwenden. Dabei kommt eine eigene Extension c1_adaptive_images zum Einsatz. Da sich dabei der Fokus aber weg von eigene ImageRenderer-Klasse hin zu Vereinfachung und Fluid ViewHelpern verschoben hat wird es hier wahrscheinlich irgendwann nochmal zu einer Namensänderung kommen.

Warum und überhaupt?

  • Bilder machen im Schnitt um die 2/3 des Gesamtdatenaufkommens einer Webseite aus, es lohnt sich also sehr, hier zu optimieren. Adaptive images sind dafür ein essentieller Baustein.
  • weniger übertragene Daten = schnellere Ladezeit
  • wohl dem, der immer und überall schnelles Internet hat. Alle anderen freuen sich über weniger Traffic und damit weniger Wartezeit (und evtl. Kosten)
  • weniger Datenvolumen für den eigenen Server benötigt
  • der Netzwerker in mir sagt, dass unnötige Daten zu vermeiden sind

Hilfe zu dieser Seite

In der fixen Leiste oben befinden sich einige Optionen, die je nach gewähltem Modus zum Rendern der Bilder verfügbar sind:

Option   
DelayVerzögerung beim Laden des Bilds, damit Page Reflows und eventuelle Platzhalter besser sichtbar werden.
Nur für Modes mit lazysizes.
  
DebugInfos zum aktuellen Bild (Breite in px, Höhe in px, Aspect Ratio) direkt aufs Bild gerendert (mit IM bzw. GM)  
JS-DebugInfos zum aktuellen Bild (Breite in px, Höhe in px, Aspect Ratio) per JavaScript aufs Bild gelegt  
Ratio-BoxEine Ratio-Box ums das Bild rendern  
ModeDer Modus zum Rendern des Bilds  

 

Responsive vs. adaptive images

Die beiden Begriffe werden oft vermischt und nicht klar voneinander abgetrennt. Ich verwende sie hier so:

  • Responsive images: Responsive sind Bilder, wenn sie sich in ihrer Breite dem umgebenden Container anpassen. Man erreicht das in der Regel durch "max-width: 100%, height: auto" im CSS. Dadurch nimmt das Bild max. 100% der Breite ein, schrumpft dann aber mit dem Container mit. Will man erreichen, dass Bilder auch hochskalieren, also den Container imemr zu 100% Breite fülle, dann verwendet man statt max-width die Eigenschaft width.
  • Adaptive images: Adaptiv sind Bilder, die in verschiedenen Größen (als Kominationen aus img, picture und source-Tags) angeboten werden. Man will damit erreichen, dass für jede Bildschirmgröße jeweils Bilder in der optimalen Größe geladen werden.

Ratio-Box

Mit Ratio-Box ist ein Wrapper-Element gemeint, das immer eine fixes Seitenverhältnis des Bilds erzwingt. Dazu wird eine CSS-Technik benutzt, die als intrinsic ratio bzw. padding-bottom hack bekannt ist. Von den hier vorgestellten Techniken ist diese Methode die einzige, die Page-Reflows komplett verhindert, da es bei den anderen Techniken mit Platzhaltern/Vorschaubildern zwangsläufig zu Rundungsfehlern kommt.

<div class="rb rb--56dot25 rb--max-width767px-75">
  <picture>
    <source media="(max-width: 767px)" data-srcset="..." srcset="..." sizes="..." />
    <img srcset="..." data-srcset="..." sizes="..." />  
  </picture>
</div>
.rb {
  position: relative;
  height: 0;
  display: block;
  width: 100%;
  /* fallback, actual padding-bottom is calculated and put in a style tag in the pages header */
  padding-bottom: 75%;
}

.rb img, .rb picture, .rb picture, .rb iframe, .rb video {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: block;
  max-width: inherit;
}

Der Trick dabei ist folgender: Der Ratio-Box mit der Klasse .rb wird per CSS eine Höhe von 0px gegeben. Durch padding-bottom wird das Element nach unten ausgedehnt, hier können wir als Wert nun (im Gegensatz zu height) einen prozentualen Wert im Verhältnis zur Breite angeben. Als Default gibt das CSS hier 75% an (was einer 4/3 ratio entspricht). Woher bekommt man hier die tatsächliche Aspect Ratio? Dies passiert über die beiden Klassen rb--56dot25 und rb--max-width767px-75, diese werden im Fluid-Template durch den ai:ratioBox Viewhelper aus der tatsächlichen Bildgrösse generiert und das zugehörige CSS in ein style-Tag im head der Seite geschrieben (s.u.).

Nachdem der wrapper jetzt die richtigen Dimensionen hat können wir darin mit position: absolute das Bild so platzieren, dass es genau 100% der Breite und Höhe einnimmt.

<ai:ratioBox file="{file}" mediaQueries="{mobile: '(max-width:767px)', default: ''}">
  ein Bild, Video, Iframe etc. hier
</ai:ratioBox>
<style type="text/css">
  .rb--56dot25{
    padding-bottom:56.25%
  }
  @media (max-width:767px){
    .rb--max-width767px-75{
      padding-bottom:75%
    }
  }
</style>

Page Reflow

Egal mit wem ich rede: Page Reflows kennt fast jeder und keiner mag sie. Ein Page Reflow ist, wenn die Seite bereits gerenderte Elemente verschieben muss, da neue Elemente (darüber oder davor) geladen wurden. Dadurch "springt" der Inhalt während dem Laden der Seite. Gerade Bilder sind oft die Ursache von Reflows, es gibt hier verschiedene Ursachen:

  • Der Browser rendert die Seite bereits, während die Bilder noch geladen werden. Bei responsive images hat er aber noch keine Informationen über die effektiven Dimensionen des Bilds und kann den benötigten Platz daher nicht reservieren.
  • Durch Rundungsfehler kann es auch bei Modi, die Platzhalter verwenden um Platz zu reservieren zu kleineren Sprüngen um einige Pixel kommen.

Rundungsfehler

Pixel sind wie Atome - unteilbar. Aus diesem Grund können unterschiedliche srcset-Bilder leicht unterschiedliche Aspect Ratios haben. Es kann daher vorkommen, dass auch Bilder, die über lazysizes eingebunden werden und einen Placeholder haben in der Höhe um wenige Pixel springen, wenn der Placeholder mit dem geladenen Bild ersetzt wird.

Rundungsfehler entstehen auch dadurch, wie der LocalCropScaleMaskHelper (L86) in TYPO3 Breiten und Höhenangaben der Bilder von float zu integer wandelt, hier wird alles als int getyped, wodurch immer abgerundet wird (aus 123,99 wird 123).

Wenn selbst kleinste Sprünge des Layouts beim Laden der Seite vermieden werden sollen, dann kommt man wahrscheinlich um eine "ratio box", die eine fixe Aspect Ratio vorgibt, nicht herum.

Weitere Bildoptimierungen

Um die Größe der Bilder weiter zu drücken sollten weitere Bildoptimierungen vorgenommen werden.

  • webp-support: WEBP-Bilder sind bei nicht merklichem Qualitätsverlust meist deutlich kleiner als Bilder im JPG-Format. Derzeit unterstützen nur Chrome, Opera und einige Android-Browser WEBP, die zusammen aber fast 3/4 Marktanteil haben. Für diese Seite nutze ich dafür die webp extension von plan2net. Die Installation ist sehr einfach. Eine Änderung am Markup ist nicht nötig, Browsern mit Support für WEBP wird beim Aufruf von Bildern durch eine passende Webserverkonfiguration automatisch WEBP ausgeliefert.
  • Bildoptimierung für JPG/PNG/GIF/SVG: Mit jpegoptim, optipng, gifsicle und svgo lassen sich auch JGP bzw. PNG Bilder weiter optimieren. Dafür kann unter TYPO3 die Extension imageoptimizer verwendet werden. Für korrekte Funktion müssen die entsprechenden Tools auf dem Server installiert sein. Für diese Seite optimiere ich nur JPG und PNG. GIF wird nicht verwendet und SVG wird bereits im Buildprozess optimiert.

Weitere Resourcen

Über Adaptive Images wurde viel geschrieben die letzten Jahre und es gibt einige wirklich lehrreiche Artikel zum Thema. Die dort erklärten Grundlagen sollte man verstanden haben um adaptive Images sicher einsetzen zu können.

Grundlage einiger Modi auf dieser Seite ist lazysizes.js:

Images & Page Reflow:

Diskussionen zum Thema intrinsic image sizes:

Client Hints

Hier war auch schon mal jemand verzweifelt genug um image innerhalb von svg zu verwenden (wenn auch anders)