responsive images demo

Responsive Images – width/height-Attribute entfernen, lazy loading & padding-bottom Trick

Für das Einbinden von Bildern im Responsive Webdesign wird häufig empfohlen die ‚width‘- und ‚height‘-Attribute im HTML-Quellcode zu entfernen. Das ist aber nicht nötig und meiner Meinung nach auch nicht gut in Hinblick auf hochauflösende Bilder.

Mit CSS kann man die im HTML festgelegten Breiten überschreiben und die Bilder so flexibel machen.

Responsive Images basics:

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

Das Bild passt sich somit immer dem Container an, wird aber nie größer als seine eigentliche Originalgröße in Pixel. Das dürfe sicherlich bekannt sein. Wenn das nicht funktioniert, liegt ein anderer „Fehler“ vor, wie ein anderer BFC durch ‚float‘ oder ähnliches.

Aber gehen wir mal zurück, auf das Problem der fehlenden ‚width‘ und ‚height‘ Attribute. Angenommen, dass Bild soll links im Text floaten. Wenn die Breiten- und Höhenattribute fehlen wird der Platz für das Bild im Layout nicht vorgehalten und der Text läuft über die gesamte Breite. Ist das Bild dann vollständig geladen, springt der Text und fließt um das Bild. Das kann je nachdem wie viele Bilder man lädt und was für ein Layout man hat, sehr hin-und-her springen. Der Browser führt jeweils einen Reflow durch.

Zugegeben, wenn wir von Responsive Images reden, ist das mit der Angabe von ‚width‘- und ‚height‘-Attributen im HTML-Quellcode schon fast wieder hinfällig. Durch die Angabe max-width: 100%; height: auto; muss der Browser die anzuzeigende Größe so oder so berechnen und das erzwingt dann den Reflow.

Hochauflösende Bilder / Retina

Bei der klassischen Einbindung von Bildern für hochauflösende Displays, aka Retina, geht man davon aus, dass man ein Bild in doppelter Größe einbindet. Bei der heutigen Varianz der Displaygrößen und Pixel-Ratios ist das um einiges komplizierter geworden, aber das ist noch mal ein anderes Thema…

Gehen wir mal von der doppelten Bildgröße und folgendem Beispiel aus:

<p>
  <img src="images2x.jpg" alt="">
  lorem ipsum
</p>

Angenommen das Bild hat in einfacher Auflösung eine Größe von 400x300px, das Retina-Bild ist dementsprechend 800px breit. Ohne weitere Angaben würde das Bild im obigen Beispiel auf größeren Bildschirmen 800px breit angezeigt werden, bzw. so breit wie der Container ist. Initial wollten wir aber dass das Bild maximal 400px breit ist.

Mit einer Breiten-Angabe width="400" im HTML wäre unser Retina-Bild auch nur max 400px breit und nicht größer.

<p>
  <img src="images2x.jpg" width="400" height="300" alt="">
  lorem ipsum
</p>

Demo: http://codepen.io/maddesigns/full/bFwnK

An dieser Stelle möchte ich nicht auf Responsive Images (Adaptive Images) eingehen, also für die richtige Bildgröße für die passende Displaybreite an zu geben.

Slides zum Thema „Responsive Images“

Lazy-Loading

Um nicht sofort alle Bilder zu laden, die nicht im Sichtbereich der Seite sind, gibt es schon seit Jahren eine Methode die man „Lazy Loading“ nennt. Alter Hut… Mit statischem Layout hatte man da kaum Probleme, mit flexiblem Layout schon. Einen faden Beigeschmack hat das allerdings, wenn Browser die Bilder ondemand laden. Man umgeht damit den Preparser des Browsers, der schon Vorarbeit beim Aufruf der Seite leistet. Das Hinzufügen von DOM-Elementen durch das Lazy Loading ist „teuer“. Das merkt man besonders bei schwächeren mobilen Endgeräten. Das Bilder sofort laden ist in dem Sinne auch problematisch, da das die gesamte Ladezeit der Seite erhöht, Stichwörter: Requests und Latenzen. Ein Abwägen und Testen der Möglichkeiten ist immer notwendig, wobei ich grundsätzlich zu Lazy Loading tendiere, wenn der Scope hauptsächlich moderne Smartphones/Tablets ist.

Eine schmale Lazy-Loading-Lösungen mit JS

Unveil.js ist ein kleines jQuery-/Zepto-Plugin, dass wahlweise auch Retina-Bilder laden kann.

<img src="img/loader.gif" data-src="img2.jpg" data-src-retina="img2-retina.jpg" />

Lazy Loading wird W3C Standard

Solch ein Verhalten soll in Zukunft eigenständig und optimiert vom Browser selbst durchgeführt werden. Durch ein Attribut soll das Laden einer Resource verzögert werden. Microsoft hat dies bereits im IE11 umgesetzt. Ein Beispiel:

<img src="example.jpg" lazyload="1" />

Ich wiederhole das nochmal – Microsoft hat ein natives „Lazy Loading“ im Internet Explorer 11 bereits integriert. Fantastisch, oder?

Allerdings ist das nicht ganz 1:1 von der Idee der JavaScript-Bibliotheken übernommen. „Lazyload“ bedeutet in dem Fall, der Browser lädt die Resource, das können z.B. auch <script> oder <video> Elemente sein, verzögert, also erst nachdem andere Resource geladen sind, auch wenn sie vorher im Dokument sind.

Das Verhalten „Bild wird erst geladen, wenn es im Sichtbereich ist“ soll nach der Resource-Priorities-Spezifikation mit dem Attribut postpone möglich sein. Einen Polyfill für postpone gibt es bereits.

Mit der aktuellen Lazy-Loading-Methode im Responsive Webdesign hat man weiterhin das Problem, dass beim Einsetzen der Bilder ein Reflow der Seite durchgeführt wird und der Text springt. Reminder: „teuer“.

padding-bottom Trick

Wenn man mit Bildern arbeitet, die ein gleichbleibendes Seitenverhältnis haben, z.B. 16:9 oder 4:3, dann kann man den benötigten Platz bereits vorhalten, so dass Text, der um das Bild fließen würde, bereits richtig positioniert ist und nicht springt wenn das Bild lädt.

Der Container, der die Bilder beinhaltet, benötigt folgende CSS-Regeln:

.parent {
  display: block; /* if inline element */
  position: relative;
  height: 0;
}

Die richtige Container-Höhe wird anhand des festen Seitenverhältnis berechnet.

Einfacher Dreisatz: 9 × 100% ∕ 16

Dieser errechnete Wert, ist der Wert, der die Box nun durch padding-bottom visuell vergrößert. Das Bild innerhalb des Containers wird absolut positioniert und mit width: 100% sowie height: 100% auf die komplette Größe der Containerbox aufgespannt. Stimmt das Seitenverhältnis nicht, erkennt man das am verzerrten Bild.

.parent {
  display: block;
  position: relative;
  height: 0;
  padding-bottom: 56.25%;
  width: 100%;
}
.parent > .child {
  display: block;
  position: absolute;
  width: 100%; 
  height: 100%;
  top: 0;
  margin: 0;
  padding: 0;
}

So kann man Bilder (in der passenden Bildschirmgröße) ondemand laden ohne dass der Text erneut ausgerichtet wird (reflow).

Wenn Bilder aber nicht mit einer Container-Breite von 100% eingebunden sind, ist die Dreisatzrechnung eine andere. Angenommen das Bild soll links im Text mit einer Breite von 33% angezeigt werden, dann ist die Berechnung des padding-bottom Abstand folgendermaßen: 9 × 33% ∕ 16

Den padding-bottom Trick beschreiben Anders Andersen & Tobias Järlund in Ihrem Smashing-Magazine Artikel Addressing The Responsive Images Performance Problem: A Case Study ausführlich.

fixed ratio Sass mixin

Da man das ja nicht immer selbst ausrechnen möchte, kann man sich hier mit einem kleinen Sass-Mixin aus dem Sass-Toolkit behelfen:

// @mixin fixed-ratiobox();
//
// stealed from https://github.com/Team-Sass/toolkit/blob/master/compass/stylesheets/toolkit/_intrinsic-ratio.scss
//
// usage: @include fixed-ratiobox(4/3, 50%, 'img, figure');
//
$intrinsic-ratio: 16/9 !default;
$intrinsic-ratio-width: 100% !default;
$intrinsic-ratio-elements: '> *' !default;
$intrinsic-ratio-extend: true !default;
$intrinsic-ratio-direction: bottom !default;

@mixin intrinsic-ratio-parent($extend: $intrinsic-ratio-extend) {
    @if $extend {
      @extend %intrinsic-ratio-parent;
    }
    @else {
      display: block;
      position: relative;
      height: 0;
    }
}

@mixin intrinsic-ratio-child($extend: $intrinsic-ratio-extend) {
  @if $extend {
    @extend %intrinsic-ratio-child;
  }
  @else {
    display: block;
    position: absolute;
    width: 100%; // !important Nuke the external styles
    height: 100%; // !important Nuke the external styles
    top: 0;
    margin: 0;
    padding: 0;
  }
}

@mixin intrinsic-ratio-ratio($ratio: $intrinsic-ratio, $width: $intrinsic-ratio-width, $direction: $intrinsic-ratio-direction) {
  padding-#{$direction}: (1 / $ratio) * $width;
  width: $width;
}

@mixin intrinsic-ratio($ratio: $intrinsic-ratio, $width: $intrinsic-ratio-width, $elements: $intrinsic-ratio-elements, $extend: $intrinsic-ratio-extend, $direction: $intrinsic-ratio-direction) {
  @include intrinsic-ratio-parent($extend);
  @include intrinsic-ratio-ratio($ratio, $width, $direction);

  @each $element in $elements {
    #{$element} {
       @include intrinsic-ratio-child($extend);
    }
  }
}

@mixin fixed-ratiobox($ratio: $intrinsic-ratio, $width: $intrinsic-ratio-width, $elements: $intrinsic-ratio-elements, $extend: $intrinsic-ratio-extend, $direction: $intrinsic-ratio-direction) {
  @include intrinsic-ratio($ratio, $width, $elements, $extend, $direction);
}

%intrinsic-ratio-parent {
  @include intrinsic-ratio-parent(false);
}

%intrinsic-ratio-child {
  @include intrinsic-ratio-child(false);
}

Anwendung des fixed ratio Mixins

.parent {
  @include fixed-ratiobox(2/1);
}

Der generierte CSS-Code:

.parent {
  position: relative;
  height: 0;
  padding-bottom: 50%;
  width: 100%;
}
.parent > * {
  display: block;
  position: absolute;
  width: 100% !important;
  height: 100% !important;
  top: 0;
  margin: 0;
  padding: 0;
}

Die Einbindung einer Box mit festem 4:3 Seitenverhältnis, welche aber nur 50% der Container-Breite einnimmt und für ‚IMG‘ oder ‚FIGURE‘ Kindelemente gilt, geht so:

.wrapperclass {
  @include fixed-ratiobox(4/3, 50%, 'img, figure');
}
.wrapperclass {
  position: relative;
  height: 0;
  padding-bottom: 37.5%;
  width: 50%;
}
.wrapperclass img, .wrapperclass figure {
  display: block;
  position: absolute;
  width: 100% !important;
  height: 100% !important;
  top: 0;
  margin: 0;
  padding: 0;
}

Wer damit herum spielen möchte, kann das mit Sassmeister machen.

Wie man vielleicht auch schon erahnen kann, ist das nicht nur hilfreich für Bilder im festen Seitenverhältnis, sondern auch allgemein für Inhaltselemente mit festem Seitenverhältnis. Diese Technik nutzt man unter anderem auch für die Einbindung von responsive Youtube-Videos. Marc Hinse beschreibt die Technik für gleiche Seitenverhältnisse in seinem Artikel Height equals width with pure CSS.

One thought on “Responsive Images – width/height-Attribute entfernen, lazy loading & padding-bottom Trick”

Kommentare sind geschlossen.