Bild-Zoom und Lupeneffekt für Website-Bilder (CSS & JS)
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:
- Tap-to-Toggle: Ein Tippen schaltet einen fest vergrößerten Zustand um. Simpel, aber ohne freie Steuerung des Ausschnitts.
- 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/pageXstattgetBoundingClientRect()gerechnet, oder dem Container fehltposition: relative. - Lupe flackert: Das Glas fängt selbst die Maus-Events ab.
pointer-events: nonesetzen. - 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