von Andy Pillip

Responsive Image Maps

Mit CSS3 lässt sich eine flexible Image Map für das Responsive Web realisieren

Mit ein bisschen CSS3 und wenig HTML Markup lassen sich Image Maps mit Rechtecken responsive realisieren, sind barrierefrei und lassen sich auch noch für hochauflösende Displays (z.B. Retina-Display beim iPad) optimieren.

In folgendem Vorschlag für Webentwickler werde ich auf einem Bild der Mitarbeiter von pressenter die Personen einzeln verlinken, wie in einer Image Map.

Der Code ist progressiv aufgebaut, ich denke also immer zuerst an kleine Bildschirme (mobile first), danach erst an Große.

Flexible Bilder (responsive Images)

Eine Basistechnik aus dem Responsive Design ist folgender einfacher CSS-Code:

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

Das gleiche Bild der Mitarbeiter bei 320 px in x-Auflösung

Damit wird das Bild in der vorgegebenen Größe (width und height in HTML) dargestellt, so lange es in seinem Container (dem Elternelement) Platz hat.

Wird der Container kleiner als das Bild, wird dieses durch height: auto verhältnistreu verkleinert. Auf Geräten mit kleinen Bildschirmen sind also bereits alle Mitarbeiter zu sehen:

Optimierung für hochauflösende Bildschirme (z.B. Retina)

Bild in Höherer Auflösung abspeichern

Damit ohne viel Technik das Bild auch auf hochauflösenden kleinen Bildschirmen gut aussieht, habe ich das Bild in der zweifachen Größe angelegt, also in 320 px · 2 = 640 px.

Damit erscheint das Bild dann auch im Querformat (~480 px) noch relativ scharf bei hochauflösenden Geräten.

Auf Bildschirmen mit einer höheren physikalischen Auflösung als 640 px in der Breite wird es also unscharf.

Größeres Bild über CSS Mediaqueries nachladen

So lange die Techniken für Responsive Images noch in Entwicklung sind, mit denen der Browser das passend aufgelöste Bild selbst lädt, behelfe ich mir mit einem einfachen CSS-Trick, von dem mich zuletzt Simon überzeugt hat:

<figure id="imgmap">
  <img src="mitarbeiter.jpg" width="640" height="181" alt=""/>
</figure>

Das img-Element und die CSS-Regel von oben sorgen bereits dafür, dass der Container #imgmap um das Bild stets auch vertikal im Seitenverhältnis mitwächst. Mit der CSS-Anweisung

#imgmap img { width: 100%; }

sorge ich dafür, dass das Bild auch über seine tatsächliche Größe von 640 px hinaus vergrößert wird.

Weil ich in CSS mit Mediaqueries Kontrolle über die Auflösung des Gerätes habe, tausche ich dort das Bild aus. Vielmehr verstecke ich das Bild, und gebe dem Container, der die gleiche Größe hat, ein Hintergrundbild:

@media (min-width: 640px) {
  #imgmap img { visibility: hidden; }
  #imgmap {
    background: url("mitarbeiter-1000px") no-repeat left top;
    background-size: 100% auto;
  }
}

Mit der CSS3-Eigenschaft background-size sorge ich dafür, dass auch das Hintegrundbild stets mitwächst.

Links über das Bild legen

Jetzt fehlen noch die Links auf die Seiten der Mitarbeiter. Diese füge ich barrierefrei und semantisch korrekt in HTML ein:

<figure id="imgmap"><img src="mitarbeiter.jpg" width="640" height="181" alt=""/>
<figcaption>
  <a id="ma1" href="mitarbeiter1.html" title="Mitarbeiter 1 kontaktieren">Mitarbeiter 1</a>
  <a id="ma2" href="mitarbeiter2.html" title="Mitarbeiter 2 kontaktieren">Mitarbeiter 2</a>
  <a id="ma3" href="mitarbeiter3.html" title="Mitarbeiter 3 kontaktieren">Mitarbeiter 3</a>
  <a id="ma4" href="mitarbeiter4.html" title="Mitarbeiter 4 kontaktieren">Mitarbeiter 4</a>
  <a id="ma5" href="mitarbeiter5.html" title="Mitarbeiter 5 kontaktieren">Mitarbeiter 5</a>
</figcaption>
</figure>

Das ähnelt eigentlich schon sehr stark dem Markup einer Imagemap.

Am Ende müssen diese Links über das Bild gelegt werden, was nur mit absoluter Positionierung über die IDs funktioniert. Die Links lassen sich natürlich nur rechteckig formen, und sollen das Bild in Spalten teilen.

#imgmap { position: relative; } /* für absolute Positionierung der Kindelemente */
a#ma1 { left: 0; width: 20%; }
a#ma2 { left: 20%; width: 20%; }
a#ma3 { left: 40%; width: 20%; }
a#ma4 { left: 60%; width: 20%; }
a#ma5 { left: 80%; width: 20%; }

Auf kleinen Bildschirmen macht es absolut keinen Sinn, dass die Mitarbeiter einzeln anklickbar sind, deshalb verstecke ich sie erst einmal, indem ich sie aus dem Container hinaus schiebe:

#imgmap { overflow: hidden; }
#imgmap a { position: absolute; top: 100%; height: 100%; }

Dadurch werden sie von Screenreadern immer noch vorgelesen, und bleiben mit der Tastatur ansteuerbar.

Wenn die Auflösung hoch genug ist, um einzelne Mitarbeiter mit dem Finger zu treffen, positioniere ich die Links an richtiger Stelle:

@media (min-width: 480px) {
  #imgmap a { top: 0; }
}

Feinschliff

Mit weiteren Basisregeln, wie z.B. text-indent, den Pseudoklassen :hover, :focus und :active sollte man die Links noch so gestalten, dass der Text nicht mehr sichtbar ist und ein netter Effekt entsteht, wenn man einen Mitarbeiter mit der Tastatur auswählt.

Für hochauflösende, große Bildschirme kann man auch noch einen Mediaquery und ein Bild mit 2000 px anlegen.

Wo diese Grenzen liegen, ob man schon bei kleineren Auflösungen größere Bilder lädt, bleibt jedem selbst überlassen. Man muss immer zwischen Ladezeiten und scharfem Bild abwägen.

Die versteckten Links sollten bei :focus wieder an die Position über dem Bild verschoben werden, um für Barrierefreiheit die Navigation mit der Tastatur zu ermöglichen.

Plan B für ältere Browserversionen

Bei allen Techniken muss man natürlich auch an Browser denken, die die modernen Techniken nicht beherrschen.

Fehlende Mediaqueries

Wenn Mediaqueries nicht zur Verfügung stehen, werden die entsprechenden CSS-Regeln ignoriert. Das bedeutet in meinem Vorschlag, dass die Mitarbeiter einfach nicht verlinkt sind, und das 640 px große Bild geladen und vergrößert wird.

Natürlich kann man überlegen, auch auf den kleinsten Bildschirmen die Mitarbeiter schon zu verlinken, dann klappt das auch in älteren Browsern.

Fehlendes background-size

In meinem Vorschlag habe ich jetzt keinerlei Rücksicht auf Browser genommen, die die CSS-Anweisung background-size nicht beherrschen. In diesen wird der Hintergrund also einfach links oben platziert und entsprechend abgeschnitten — wir hatten auch ein Projekt, wo das optisch funktioniert.

Man kann abwägen, ob es tatsächlich so viele Browser(versionen) gibt, die zwar Mediaqueries, aber kein background-size beherrschen.

In dem hier genannten Projekt habe ich den modernizr benutzt, der die Fähigkeiten des Browsers per JavaScript überprüft. Nur wenn der Browser background-size beherrscht, wende ich die CSS-Regel zum Austauschen des Bildes an.

Dadurch dass ich in meiner Lösung ein echtes img-Element verwende, lässt sich die Image-Map auch komplett ohne ausgetauschtes Bild realisieren.

Alternativen

Eine Alternative wäre, das Bild der Mitarbeiter in einzelne Elemente zu zerstückeln, und mit Links zu versehen. Über CSS-Sprites wäre auch der Vorteil von nur einem Request gegeben.

Diese Lösung ist aber in der Wartung sehr aufwändig: der CSS-Code ist komplexer, und bei jeder Bildänderung müssen die Einzelbilder (in allen Auflösungen) überarbeitet werden.

Außerdem müssen die Sprite-Positionen für die Flexibilität in % angegeben werden, wenn sich also Mitarbeiter nahe stehen, kann es durch Rundungsfehler durch Überlappungen der Bilder kommen.