Responsive Images – <picture>, srcset, sizes & Co.

responsiveimages

Flexible Bilder sind ein wichtiger Bestandteil von responsiven Websites. Doch leider stellte genau dieses Thema Web Designer in den vergangenen Jahren vor enorme Herausforderungen. Ohne Scripte war es bisher nicht möglich Bilder ohne Performance- oder Qualitätsverluste auf allen Displaygrößen darzustellen. Und selbst mit der Unterstützung von Scripten waren einige Änderungen – z. B. die Veränderung des Bildausschnitts – eine mehr als lästige Aufgabe. Mit <picture>, srcset & sizes sind neue HTML-Elemente und -Attribute in die Spezifikation gewandert, mit deren Hilfe sich viele Probleme bald lösen werden.

Workshop: CSS – The Next Level

Wir machen dich fit für die Zukunft des Web! In diesem Workshop lernst du die spannendsten neuen CSS-Techniken anhand praktischer Übungen kennen.

Berlin, 26. September 2016
Berlin, 11. November 2016

img vs. background

In diesem Beitrag geht es um Bilder im HTML-Code, also um inhaltlich relevante Grafiken. Bilder die per CSS einem Element als background zugewiesen wurden, können auch heute schon über Media Queries ausgetauscht werden. Im HTML-Code hingegen existierten bisher keine Media Queries, daher war der Austausch dort nicht ohne weiteres möglich.

Die bisherigen Lösungen

Mitte 2014 arbeiten die meisten Websites noch mit einem Kompromiss. Es wird das gleiche Bild für alle Displaygrößen und Displaytechnologien ausgespielt. Mit folgender CSS-Angabe verhält sich das Bild flexibel:


img {
  max-width: 100%;
  height: auto;
}

Diese Vorgehensweise hat bekanntlich große Nachteile. Entweder werden auf kleinen Displays zu große Dateien geladen, was der Performance schadet, oder das Bild wird über seine tatsächliche Breite hinaus skaliert. Letzteres führt zu schlechter Bildqualität auf großen Displays. Hochauflösende Displays werden gar nicht berücksichtigt.

Um diese Probleme zu beheben, wurden verschiedene Tricks und Scripte verwendet. Der Vollständigkeit halber möchte ich auch einige diese Techniken kurz erwähnen.

Downsampling

Um sowohl auf normalen als auch auf hochauflösenden Displays eine gute Bildqualität zu erreichen, wird das Bild oft in doppelter Größe geladen. Über die Größenattribute von HTML skaliert man das Bild auf gewünschte Größe herunter. Ziel ist es, die Pixeldichte der Grafiken soweit zu erhöhen, dass sie der DPR von hochauflösenden Geräten entspricht. Diese Methode nennt sich Downsampling.

Downsampling auf der Website von Bootstrap 2.3
Downsampling auf der Website von Bootstrap 2.3

Optisch erreicht man so auf allen Displays ein perfektes Ergebnis, allerdings werden auf niedrigauflösenden Geräten ebenfalls hochauflösende Grafiken geladen. Durch starke Kompression musste das allerdings nicht zwangläufig zu schlechter Performance führen. Ich setze diese Technik teilweise auch hier im Blog ein.

Adaptive Images

Das Script Adaptive Images dürfte den meisten von euch ein Begriff sein. Wie der Name bereits andeutet, handelt es sich um eine adaptive Lösung. Mit Hilfe eines PHP-Scripts, sowie einer .htaccess-Datei werden Bilder auf dem Server automatisch in verschiedene Größen geschnitten. Anschließend prüft das Script wie groß die Bildschirmauflösung des Anwenders ist und spielt das passende Bild aus.
Das Script bietet sich als Lösung durchaus an, hat aber auch klare Schwachstellen. Es ist beispielsweise nicht möglich das Bildmotiv zu verändern. Ebenfalls nicht berücksichtigt werden mehrspaltige Layouts oder hochauflösenden Displays.

Focal Point

Ein typisches Problem mit Bildern im Responsive Design ist der Bildausschnitt. Ein Foto kann zwar technisch problemlos auf Smartphone-Größe herunterskaliert werden, oft gehen dadurch aber wichtige Bilddetails verloren. Es ist also notwendig den Bildausschnitt zu verändert.
Gelöst werden kann dieses Problem mit einer CSS-Technik namens Focal Point. Dabei wird bestimmt, welcher Punkt immer sichtbar sein soll. Mit Hilfe eines Container-Elements und negativer margin-Angaben, wird das Bild anschließend ab einem bestimmten Breakpoint gezoomt und verschoben.
Eine Beispieldatei zu diesem Thema findet ihr hier. Es existiert auch bereits ein Framework namens Focal Point, dass sich unkompliziert in die Website integrieren lässt.

Die Anwendungsfälle (Use Cases) für Responsive Images

Um die soeben beschriebenen Probleme in Zukunft mit reinem HTML lösen zu können, hat sich die Responsive Images Community Group gegründet. Die Gruppe hat mehrere Jahre lang Lösungsvorschläge erarbeitet und hitzig diskutiert.

Logo der Responsive Images Community Group
Logo der Responsive Images Community Group

Im Rahmen der Diskussion wurden u.a. die möglichen Anwendungsfälle für Responsive Images formuliert:

  1. Bilder sollen mit unterschiedlicher Auflösung für normale und hochauflösende Displays ausgegeben werden
  2. Bilder innerhalb eines flexiblen Web-Layouts (responsive Layout) sollen mit unterschiedlicher Abmessung für verschiedene Viewport-Größen ausgegeben werden
  3. Es sollen unterschiedliche Bildausschnitte, Seitenverhältnisse oder Motive für verschiedene Viewport-Größen verwendet werden (Art Direction)
  4. Es sollen unterschiedliche Dateiformate für unterschiedliche Browser verwendet werden
  5. Kombinationen der letzten vier Punkte

Um diese Anwendungsfälle zu lösen, gibt es nun ein weiteres HTML-Element namens <picture>, die neuen Attribute srcset und sizes und die Werte x, w und vw.
In Kombination kann mit diesem Repertoir an neuem Markup jeder der oben beschriebenen Anwendungsfälle gelöst werden.

Notwendige Informationen für die perfekte Bildgröße

Damit ihr versteht wie das neue Markup eingesetzt wird, solltet ihr euch kurz folgende Tabelle anschauen. Um für jeden Anwendungsfall das perfekte Bild laden zu können, müssen dem Browser die folgenden vier Informationen vorliegen.

Kennt der Browser Kennt der Entwickler
Größe des Viewports X
Bildschirmauflösung X
Abmessungen der Bilddatei X
Größe in der das Bild gerendert werden soll X

Der Browser kennt leider nicht alle notwendigen Informationen. Aus diesem Grund ist es notwendig, dass der Entwickler manuelle Hinweise vergibt. Dazu später mehr.

Bilder für unterschiedliche Display-Qualitäten ausgeben

Beginnen wir mit einem einfachen Anwendungsfall. Wir möchten eine Grafik in normaler Auflösung für Standard-Displays, und in hoher Auflösung für hochauflösende Displays ausgeben. Schaut euch dazu folgenden Code an:


<img src="bild.jpg" srcset="bild.jpg 1x, bild@2x.jpg 2x" alt="">

Zunächst wird ein ganz gewöhnlicher <img>-Tag verwendet. Über das src-Attribut wird die Bildquelle definiert. Soweit nichts Neues.

srcset

Mit srcset definiert ihr ein Set von Bildquellen und überschreibt damit das src-Attribut. Die einzelnen Quellen innerhalb von srcsetwerden mit Komma getrennt.

x-Wert

Neben den Dateinamen der Bilder seht ihr noch den sog. x-Wert. Dieser Wert bestimmt bei welchem DPR das Bild geladen werden soll. 1x entspricht einem normalen Display mit einfacher Pixeldichte, 2x steht für hochauflösende Displays mit einer Pixeldichte von 2 (z. B. das Retina-Display von Apple), 3x und mehr steht für noch höher auflösende Displays wie das des HTC One etc.

Der oben gezeigte Code lädt folglich das bild.jpg auf normalen Displays und bild@2x.jpg auf hochauflösenden Displays. Wenn ein Browser das neue srcset-Attribut nicht kennt, springt src als Fallback-Lösung ein.

Beispiel anzeigen

Bilder entsprechend der Viewport-Breite austauschen

Kommen wir nun zu einem weiteren Anwendungsfall. Der Browser soll immer das passende Bild für die aktuelle Viewport-Breite verwenden: Auf großen Displays sollen also große Bilder und auf kleinen Displays kleine Bilder geladen werden. Schaut euch dazu diesen Code an:


<img src="small.jpg" srcset="small.jpg 320w, medium.jpg 600w, large.jpg 900w" alt="">

Wie im letzten Beispiel wird zunächst ein normaler <img>-Tag mit src-Attribut verwendet. Das srcset-Attribut überschreibt in kompatiblen Browser das src-Attribut und stellt eine Liste mit verschiedenen Bildquellen bereit. Dieses Mal hat der Browser die Wahl zwischen drei Grafiken: small.jpg, medium.jpg und large.jpg.

Unterschiedliche Bildgrößen in unterschiedlichen Viewports
Funktionsweise des Beispiels in einem kompatiblen Browser

w-Wert

Neu in diesem Beispiel ist der w-Wert. Er beschreibt die physikalische Breite des Bildes in Pixeln – also die Breite die ihr beispielweise in Photoshop innerhalb des »Für Web speichern«-Dialogs sehen könnt. Der w-Wert muss manuell angegeben werden, da der Browser die Breite des Bildes nicht kennt.

Anzeige der physikalischen Bildgröße in Photoshop
Anzeige der physikalischen Bildgröße in Photoshop

Der oben gezeigte Code führt also dazu, dass der Browser bei Viewports unter 320 Pixel Breite die Grafik small.jpg lädt. Sobald der Viewport größer als 320 Pixel ist, wird medium.jpg geladen. Diese Grafik ist laut unserer Angabe 600 Pixel breit. Ab 600 Pixel wird daher large.jpg geladen.

Beispiel anzeigen

Bilder in flexiblen, mehrspaltigen Layouts

Kommen wir nun zu einem komplexeren Beispiel. Das Layout der Seite verändert die Anzahl der Spalten von einspaltig in der Smartphone-Version über zweispaltig in der Tablet-Version hin zu dreispaltig in der Desktop-Version. In einem solchen Fall kann es vorkommen, dass die Bilder in größeren Viewports, kleiner dargestellt werden.

Responsive Images in mehrspaltigen Layouts
Funktionsweise des Beispiels in einem kompatiblen Browser

Bisher haben wir die Bilder anhand der Viewport-Breite ausgetauscht. Bei mehrspaltigen Layouts macht diese Vorgehensweise keinen Sinn mehr. Damit der Browser das perfekte Bild laden kann, muss er alle vier Informationen der weiter oben gezeigten Tabelle kennen. Da er allerdings weder die Abmessungen der Bilder kennt, noch weiß wie breit das Bild dargestellt werden soll, müssen wir ihm nun zwei manuelle Hinweise mitteilen. Schaut euch dazu den folgenden Code an:


img {
  width:100%;
  height:auto;
}

@media screen and (min-width:28em) {
  img {
    width:50%;
  }
}

@media screen and (min-width:50em) {
  img {
    width:33%;
  }
}

<img 	

srcset=" large.jpg 900w,
      	 medium.jpg 600w,
      	 small.jpg 320w"

sizes="	 (min-width: 50em) 33vw,
         (min-width: 28em) 50vw,
         100vw"

src="small.jpg"

alt="" 

/>

srcset & sizes

Beginnen wir mit den Bestandteilen die wir schon kennen. <img>, src und srcset sind bekannt: Wir laden ein Bild, legen mit src eine Standard-Grafik fest und definieren über srcset eine Liste an Bildquellen. Für jede Bildquelle legen wir fest wie breit die Grafik in Pixeln ist.
Bisher unbekannt ist das sizes-Attribut. Über sizes wird festgelegt, wie breit eine Grafik dargestellt werden soll. Hier teilen wir dem Browser also die zweite fehlende Information mit. Innerhalb von sizes können nun verschiedene Rahmenbedingungen beschrieben werden – in diesen Beispiel drei, da wir drei verschiedene Layout-Ansichten haben. Jede Rahmenbedingung besteht dabei aus einem optionalen Media Query der die Viewport-Breite beschreibt, und der Breite des Bildes, hier angeben in der Einheit vw (Viewport-Width = Viewportbreite).
Eine Angabe wie (min-width: 28em) 50vw bedeutet also: Ab 28em Viewport-Breite soll das Bild die Hälfte (50%) des Viewports einnehmen. Mit (min-width: 50em) 33vw legen wir die Regel für das dreispaltige Layout fest. Ab 50em soll ein Bild ein Drittel des Viewports einnehmen. Als letztes muss immer auch noch der Standard festgelegt werden. 100vw entspricht dabei der vollen Breite.
Neben der Einheit vw sind auch alle anderen CSS-Einheiten wie px, em und sogar die calc()-Funktion möglich.

Ein Rechenbeispiel

Der Browser wählt im zuletzt gezeigten Beispiel das passende Bild automatisch aus. Wenn der Viewport beispielsweise 700 Pixel breit ist sieht die Berechnung folgendermaßen aus:

700 Pixel ist mehr als 28em (448px) und weniger als 50em (800px). Das Bild soll demnach die Hälfte der Viewport-Breite einnehmen (entspricht 350px). Da 350 Pixel mehr ist, als die physikalische Breite von small.jpg (320w) wird medium.jpg (600w) geladen.
Wenn der Anwender ein hochauflösendes Display mit einer DPR von 2 verwendet, multipliziert der Browser den benötigten Wert mit 2. Das Bild müsste dann mindestens 700 Pixel breit sein. Auf einem Retina-Display verwendet der Browser daher large.png (900w).

Bitte beachtet auch, dass der Browser keine kleineren Version eines Bildes mehr nachlädt, wenn er bereits ein höher auflösendes bzw. größeres Bild geladen hat.

Beispiel anzeigen

Keine Kontrolle bei srcset & sizes

Beachtet bitte, dass ihr nicht exakt bestimmen könnt welches Bild der Browser lädt. Die geeignetste Grafik kann der Browser nämlich selbst bestimmen. In den meisten Fällen wird die obige Beispiel-Berechnung zutreffen, in Zukunft ist es aber denkbar, dass Kriterien wie die Bandbreite oder individuelle Benutzereinstellungen Einfluss auf die Auswahl des Browsers nehmen. Der Benutzer könnte beispielsweise festlegen, dass im WLAN immer das Bild mit der besten Qualität verwendet wird. Im 3G-Netz lädt der Browser das Bild mit der geringsten Dateigröße.
Da ihr nicht verlässlich sagen könnt welches Bild geladen wird, bieten sich srcset und sizes nur für unterschiedliche Größen und Qualitätsstufen des selben Motivs an.

Art Direction – Das Motiv verändern

Kommen wir nun zum sog. Art Direction Use Case. Hierbei soll das Bild sichtbar ausgetauscht werden. Es ist beispielsweise denkbar den Bildausschnitt oder das Seitenverhältnis zu verändern. Auch ein kompletter Austausch der Grafik ist vorstellbar: Eine Infografik mit starker horizontaler Ausrichtung lässt sich auf dem Smartphone beispielsweise ins Hochformat drehen um auch auf kleinen Bildschirmen erkennbar zu bleiben.

Das <picture>-Element

Erst wenn ihr etwas aus dem Bereich Art Direction umsetzten möchtet, ist das neue HTML-Element <picture> mit von der Partie. Es dient als Container-Element für verschiedene Bildquellen. Die Bildquellen werden dabei über das HTML-Element <source> definiert.


<picture>
  <source media="(min-width: 38em)" srcset="art-direction-horizontal.jpg">
  <source srcset="art-direction-vertical.jpg">
  <img src="art-direction-vertical.jpg" alt="">
</picture>

Mit dem hier abgebildeten Code wird die Grafik ausgetauscht, sobald der Viewport 38em überschreitet. Auf großen Bildschirmen wird art-direction-horizontal.jpg verwendet, auf kleinen Bildschirmen art-direction-vertical.jpg.

Art Direction mit dem picture-Element
Funktionsweise des Beispiels in einem kompatiblen Browser

<source>, sourceset & media

Innerhalb von <picture> gebt ihr verschiedene Bildquellen an. Die Quellen werden von oben nach unten gelesen und der erste Treffer wird geladen. Die Reihenfolge ist also entscheidend. Als letztes notiert ihr mit <img src=" "> eine Fallback-Lösung für inkompatible Browser.
Innerhalb von <source> wird über das media-Attribut der Media Query notiert der für diese Bildquelle gelten soll. Anschließend legt ihr über srcset die Bildquellen fest. Ihr könnt wie im Beispiel gezeigt auch nur eine Quelle angeben.

Beispiel anzeigen

Art Direction und hochauflösende Displays

Der Vollständigkeit halber möchte ich euch auch noch ein etwas komplexeres Beispiel mit verschiedenen Bildquellen innerhalb von srcset zeigen. Das Beispiel verwendet drei unterschiedliche Quellen in jeweils zwei Qualitätsstufen.


<picture>
  <source media="(min-width: 56.25em)" srcset="large.jpg 1x, large@2x.jpg 2x">
  <source media="(min-width: 37.5em)" srcset="medium.jpg 1x, medium@2x.jpg 2x">
  <source srcset="small.jpg 1x, small@2x.jpg 2x">
  <img src="fallback.jpg" alt="">
</picture>

Beispiel anzeigen

Verschiedene Dateiformate

Mit Hilfe von <picture> ist es auch möglich verschiedene Dateiformate auszugeben. In diesem Fall kommt innerhalb von <source> das type-Attribut zum Einsatz. Über type definiert ihr den MIME-Type des Bildes. Das folgende Beispiel bietet die Grafiken sowohl als JPG als auch im Format WEB-P an. Mit WEB-P kompatible Browser wie Chrome laden das neue Format, alle anderen Browser erhalten die JPG-Grafik.


<picture>
  <source media="(min-width: 56.25em)" srcset="large.webp" type="image/webp">
  <source media="(min-width: 56.25em)" srcset="large.jpg">

  <source media="(min-width: 37.5em)" srcset="medium.webp" type="image/webp">
  <source media="(min-width: 37.5em)" srcset="medium.jpg">

  <source srcset="small.webp" type="image/webp">
  <source srcset="small.jpg">
  <img src="fallback.jpg" alt="">
</picture>

Beispiel anzeigen

Browser-Support

Zum Veröffentlichungszeitpunkt dieses Beitrags steht der native Browsersupport von Chrome und Firefox unmittelbar bevor. Die Details entnehmt ihr bitte der Website Can I Use:

Benutzt srcset, sizes und <picture> ab sofort!

Ihr könnt die in diesem Beitrag vorgestellten Techniken ab sofort einsetzen, denn es gibt native Fallback-Lösungen. Ein inkompatibler Browser zeigt die Grafik innerhalb von <img src=" "> an.

Darüber hinaus existiert das bekannte Polyfill picturefill.js mittlerweile in einer überarbeiteten Version. Ihr müsst das Script lediglich im <head> der Seite einbinden. Picturefill.js rüstet sowohl den Browsersupport für das <picture> Element als auch für sourceset und sizes nach. Bitte beachtet, dass picturefill.js mindestens in Version 2.3.1 eingebunden werden sollte! Details dazu entnehmt ihr bitte diesem Artikel.

Picturefill.js korrekt einbinden

Wenn ihr ohne das <picture>-Element arbeitet, bindet das Script wie folgt ein:


<script src="picturefill.js" async></script>

Wenn ihr das <picture>-Element einsetzt, und nicht bereits HTML5Shiv verwendet, ergänzt den Code wie hier gezeigt:


<script>
// Picture element HTML5 shiv
document.createElement( "picture" );
</script>
<script src="picturefill.js" async></script>

Beispiel mit picturefill.js anzeigen

Funktionen in Chrome Canary aktivieren

Wenn ihr die neuen Funktionen in der Entwickler-Version von Chrome (Chrome Canary) vorab aktivieren wollt, ladet Chrome Canary herunter und gebt folgenden Befehl in die Adresszeile ein:

chrome://flags/#enable-experimental-web-platform-features

Anschließend aktiviert ihr die experimentellen Browser-Funktionen und startet Chrome neu.

Kompatibilität von Validatoren

Die bekannten HTML-Validatoren validator.w3.org und validator.nu unterstützen die neue HTML-Spezifikation ab sofort.

Responsive Images & CMS

WordPress

Für WordPress existieren verschiedene Plugins, u.a. dieses hier. Das Plugin wurde von der RICG und dem WordPress-Core-Team entwickelt.

Contao

Contao unterstützt »Responsive Images« nativ seit Version 3.4.

src-n

Der Vollständigkeit halber möchte ich auch das src-n-Attribut erwähnen, da es in einigen Blogs bereits beschrieben wurde. Das src-n-Attribut war in der Diskussion, wird aber nicht weiterentwickelt. Ihr braucht euch damit nicht zu beschäftigen.

Links / Quellen