Bild-Zoom und Lupeneffekt für Website-Bilder (CSS & JS)

Website erstellen

Wer Produkte, Grafiken oder Detailaufnahmen zeigt, kennt das Problem: Auf dem Bildschirm wirkt jedes Bild klein, und Kunden können Materialstruktur, Beschriftungen oder feine Details nicht erkennen. Ein Zoom- oder Lupeneffekt löst das, ohne dass Nutzer auf eine separate Seite wechseln müssen. Dieser Beitrag zeigt drei erprobte Techniken – einen CSS-Hover-Zoom, eine echte JavaScript-Lupe und fertige Libraries – mit vollständigem, funktionierendem Code, den Sie direkt einsetzen können. Am Ende wissen Sie, welche Variante zu Ihrem Projekt passt und welche Fallstricke Sie vermeiden müssen.

Welche Zoom-Variante passt zu Ihrem Fall?

Es gibt drei grundlegend verschiedene Muster, die oft in einen Topf geworfen werden:

  • Inner-Zoom (Hover-Zoom im Bild): Der Bildausschnitt unter dem Mauszeiger wird direkt im Bildrahmen vergrößert. Ideal für Produktfotos in Listen und Galerien.
  • Lupe (Magnifier-Glas): Ein kleines rundes oder eckiges Fenster folgt dem Cursor und zeigt den Ausschnitt vergrößert – wie eine echte Lupe. Wirkt besonders bei technischen Zeichnungen oder Karten.
  • Zoom-zur-Seite / Lightbox: Beim Klick öffnet sich das Bild groß über der Seite, oft mit Pan- und Pinch-Zoom. Das ist der Standard für Content-Bilder und mobile Geräte.

Die Wahl hängt vom Gerät ab: Inner-Zoom und Lupe setzen auf mousemove und funktionieren nur mit Maus. Für Touch brauchen Sie zwingend eine Klick-/Tap-Variante (siehe unten).

Voraussetzung: ein ausreichend großes Quellbild

Der wichtigste Punkt zuerst, weil er über Erfolg oder Enttäuschung entscheidet: Ein Zoom kann nur Details zeigen, die im Quellbild vorhanden sind. Zeigen Sie ein Foto mit 600 px Breite an und vergrößern es 2,5-fach, arbeitet der Browser mit 1.500 px – die aber nicht existieren, also wird das Ergebnis unscharf und pixelig.

Faustregel: Das geladene Bild sollte mindestens so viele Pixel haben wie Anzeigebreite × Zoomfaktor. Bei 2,5-fachem Zoom eines 600-px-Rahmens brauchen Sie also ein Quellbild mit ~1.500 px Breite. Komprimieren Sie es trotzdem sauber (WebP oder AVIF, Qualität 75–82), damit die Ladezeit nicht leidet – ein großes, unkomprimiertes Zoombild ist einer der häufigsten Gründe für schlechte Core-Web-Vitals-Werte auf Produktseiten.

Variante 1: Inner-Zoom mit reinem CSS und wenig JavaScript

Diese Lösung kommt fast ohne JavaScript aus. Das Prinzip: Der Container trägt das große Bild als Hintergrund, darüber liegt dasselbe Bild als <img>. Beim Hover wird das <img> ausgeblendet und gibt den vergrößerten Hintergrund frei, dessen Position dem Cursor folgt.

<figure class="zoom" id="produkt">
  <img src="/img/produkt-1500.webp" alt="Lederrucksack, Nahaufnahme der Naht">
</figure>
.zoom {
  position: relative;
  overflow: hidden;
  background-repeat: no-repeat;
  background-size: 220%;   /* Zoomfaktor 2,2 */
  cursor: zoom-in;
}
.zoom img {
  display: block;
  width: 100%;
  transition: opacity .2s ease;
}
.zoom:hover img { opacity: 0; }
const box = document.getElementById('produkt');
const src = box.querySelector('img').src;
box.style.backgroundImage = `url('${src}')`;

box.addEventListener('mousemove', (e) => {
  const rect = box.getBoundingClientRect();
  const x = ((e.clientX - rect.left) / rect.width) * 100;
  const y = ((e.clientY - rect.top) / rect.height) * 100;
  box.style.backgroundPosition = `${x}% ${y}%`;
});

Der Trick steckt in den Prozentwerten: background-position: 50% 50% richtet den Mittelpunkt des Bildes am Mittelpunkt des Rahmens aus – so bleibt die Bewegung ohne aufwändige Pixelrechnung immer im Rahmen. Den Zoomfaktor ändern Sie allein über background-size.

Variante 2: Eine echte Lupe mit JavaScript

Wenn ein sichtbares Lupenglas dem Cursor folgen soll, führt kein Weg an JavaScript vorbei. Wichtig ist, mit getBoundingClientRect() und clientX/clientY zu rechnen – nicht mit offsetLeft/pageX, die bei gescrollten oder verschachtelten Layouts falsche Werte liefern (ein häufiger Fehler in Copy-Paste-Snippets).

<div class="lupe-wrap">
  <img id="karte" src="/img/karte-2000.webp" alt="Detailkarte des Wanderwegs">
</div>
.lupe-wrap { position: relative; display: inline-block; }
.lupe-wrap img { display: block; width: 100%; }
.lupe-glas {
  position: absolute;
  width: 150px; height: 150px;
  border: 3px solid #fff;
  border-radius: 50%;
  box-shadow: 0 2px 10px rgba(0,0,0,.4);
  background-repeat: no-repeat;
  pointer-events: none;   /* Events fallen durch aufs Bild */
  display: none;
}
function lupe(imgId, zoom = 2.5) {
  const img = document.getElementById(imgId);
  const glas = document.createElement('div');
  glas.className = 'lupe-glas';
  glas.style.backgroundImage = `url('${img.src}')`;
  img.parentElement.appendChild(glas);

  img.addEventListener('mousemove', (e) => {
    const rect = img.getBoundingClientRect();
    const x = e.clientX - rect.left;   // Cursor relativ zum Bild
    const y = e.clientY - rect.top;

    // außerhalb des Bildes ausblenden
    if (x < 0 || y < 0 || x > rect.width || y > rect.height) {
      glas.style.display = 'none';
      return;
    }
    glas.style.display = 'block';

    const gw = glas.offsetWidth / 2;
    const gh = glas.offsetHeight / 2;
    glas.style.backgroundSize = `${rect.width * zoom}px ${rect.height * zoom}px`;
    glas.style.left = `${x - gw}px`;
    glas.style.top  = `${y - gh}px`;
    glas.style.backgroundPosition = `-${x * zoom - gw}px -${y * zoom - gh}px`;
  });

  img.addEventListener('mouseleave', () => { glas.style.display = 'none'; });
}

lupe('karte', 2.5);

Zwei Details sind entscheidend: pointer-events: none auf dem Glas sorgt dafür, dass die Maus-Events weiterhin das darunterliegende Bild erreichen – sonst würde die Lupe unter dem eigenen Rand „hängenbleiben“. Und der .lupe-wrap muss position: relative tragen und das Bild an seiner oberen linken Ecke sitzen, damit die absolut positionierte Lupe korrekt platziert wird.

Touch-Geräte: Hover gibt es dort nicht

Auf Smartphones und Tablets existiert kein mousemove-Hover. Ein reiner Hover-Zoom bleibt dort schlicht wirkungslos. Zwei saubere Wege:

  1. Tap-to-Toggle: Ein Tippen schaltet einen fest vergrößerten Zustand um. Simpel, aber ohne freie Steuerung des Ausschnitts.
  2. Lightbox mit Pinch-Zoom: Beim Tap öffnet sich das Bild bildschirmfüllend, der Nutzer zoomt mit der nativen Zwei-Finger-Geste. Das ist auf Touch klar die beste Nutzererfahrung.

Prüfen Sie das Eingabegerät sauber per Media Query statt über die Bildschirmbreite:

const kannHovern = window.matchMedia('(hover: hover) and (pointer: fine)').matches;
if (kannHovern) {
  lupe('karte', 2.5);   // Lupe nur für Maus-Nutzer
} else {
  // hier Lightbox / Tap-Zoom initialisieren
}

(hover: hover) ist zuverlässiger als eine Breitenabfrage, weil auch große Touch-Tablets in Landscape breiter als ein kleines Notebook sein können.

Variante 3: Fertige Libraries statt Eigenbau

Für den produktiven Einsatz lohnt oft eine erprobte Bibliothek – sie deckt Touch, Barrierefreiheit und Sonderfälle bereits ab.

  • medium-zoom – sehr leichtgewichtig, Klick-zum-Vergrößern wie auf Medium.com. Aufruf genügt: mediumZoom('img.zoombar'). MIT-Lizenz, ideal für Content- und Blogbilder.
  • Drift (von imgix) – klassischer Produkt-Zoom mit Ausschnitt in einer Seitenfläche. Sehr passend für Shops.
  • Fancybox – umfangreiche Lightbox inklusive Zoom, Pan und Pinch, auch für Galerien. Für kommerzielle Websites ist eine kostenpflichtige Lizenz nötig, privat/Open-Source ist die Nutzung frei.

Nutzen Sie WordPress oder WooCommerce, ist ein Produkt-Zoom oft schon integriert oder per Plugin ergänzbar – dann sparen Sie sich eigenen Code und die Wartung bei künftigen Theme-Updates.

Typische Fehler und ihre Lösung

  • Zoom ist unscharf: Quellbild zu klein. Größeres Bild einbinden (siehe oben) oder Zoomfaktor senken.
  • Lupe sitzt versetzt: Es wurde mit offsetLeft/pageX statt getBoundingClientRect() gerechnet, oder dem Container fehlt position: relative.
  • Lupe flackert: Das Glas fängt selbst die Maus-Events ab. pointer-events: none setzen.
  • Layout-Sprünge beim Laden: Setzen Sie feste width/height-Attribute am <img>, damit der Browser den Platz reserviert.
  • Zoom lädt zu langsam: Große Quellbilder per loading="lazy" nachladen und in WebP/AVIF ausliefern.

FAQ

Brauche ich für den Zoom wirklich ein zweites, größeres Bild? Sie brauchen mindestens ein Bild, dessen Pixelbreite über der Anzeigebreite liegt – idealerweise Anzeigebreite mal Zoomfaktor. Ein separates zweites Bild ist nicht nötig; es reicht, das eine Bild groß genug zu laden und per CSS kleiner darzustellen.

Funktioniert der Hover-Zoom auf dem Smartphone? Nein. Touch-Geräte kennen kein Hover. Prüfen Sie mit matchMedia('(hover: hover)') und bieten Sie für Touch eine Tap- oder Lightbox-Lösung mit Pinch-Zoom an.

Schadet ein Zoom-Skript der Ladezeit oder dem Ranking? Nur, wenn Sie große Bilder unkomprimiert laden oder blockierendes JavaScript einbinden. Mit loading="lazy", defer beim Script und modernen Bildformaten bleibt der Effekt performant und wirkt sich nicht negativ auf die Core Web Vitals aus.

→ Mehr zum Thema: Alle Artikel unter Website erstellen