Powiększanie miniaturki obrazka (lightbox w stylu medium.com)

Zdjęcie autora
Lindus One
Autor:
Lindus One
Data Publikacji:
Aktualizacja:

∼ 20 linijek czystego (vanilla) javascript bez dodatkowych bibliotek i mamy powiększanie obrazka à la medium.com z wyjściem awaryjnym gdy javascript jest wyłączony. Dla urozmaicenia kilka wariantów powiększania. Ultra lekki „lightbox” jako przykład połączenia javascript z CSS.

Kod html, css i javascript

HTML

Podstawowy kod html dla miniaturki z powiększeniem. W linku ścieżka do pełnego obrazka, klasa CSS .u-blowUpImg i zagnieżdżony obrazek miniaturki.

<!-- Link do powiększenia z klasą "u-blowUpImg", przy wyłączonym javascript to wyjście awaryjne (fallback), 
powiększony obrazek wyświetli się bez animacji. Dopóki nie klikniemy przeglądarka nie pobierze obrazka. -->
<a class="u-blowUpImg" href="full-size-img.png">
    <!-- Miniaturka -->
    <img src="thumbnail.png" alt="Image description">
</a>

CSS

.u-blowUpImg:hover {
  cursor: zoom-in; /* Kursor przybliżenia */
}

Javascript

Skrypt w sekcji head. Po załadowaniu DOM do każdego elementu z klasą CSS .u-blowUpImg dodawana jest obsługa kliknięcia z powiększeniem. Na powiększeniu obsługa kliknięcia ukrywającego pełną wersję obrazka. Jeśli obsługa javascript jest wyłączona to powiększenie bez animacji.

Plik powiększania pobiera się po kliknięciu więc w przypadku wolnego połączenia obraz pojawi się w trakcie animacji. Remedium na to dalej.

<script>
    // Po załadowaniu strony
    document.addEventListener("DOMContentLoaded", function() {
        // <div> na powiększoną wersję obrazka jako tło
        let backgroundCanvas = document.createElement("div");
        // Style CSS. Długość animiacji pow/pom, kursor, środek ekranu, ukrycie.
        backgroundCanvas.style.cssText = "position: fixed; top: 50%; left: 50%; width: 0; height: 0; z-index: 1; \
        background: rgba(0,0,0,0.9) none center/contain no-repeat; transition: all .8s ease-out; cursor: zoom-out;";
        // Dodanie do body jako ostatni element
        document.body.appendChild(backgroundCanvas);
        // Po kliknięciu w powiększony obrazek zamknięcie powiększenia (width:0; height:0)
        backgroundCanvas.onclick = function() { 
            backgroundCanvas.style.inset = "50% auto auto 50%"; //top right bottom left
            backgroundCanvas.style.width = "0";
            backgroundCanvas.style.height = "0";
        };
        // Kolekcja wszystkich elementów (miniaturek) z .u-blowUpImg
        let zoomInImgLinks = document.getElementsByClassName("u-blowUpImg");
        // Dodanie obsługi kliknięcia na każdej miniaturce
        for(var i=0; i<zoomInImgLinks.length; ++i) zoomInImgLinks[i].addEventListener("click", function(e) {
            e.preventDefault();// Nie otwieraj linka i użyj javascript do powiększenia
            // Pokaż obrazek z href i animuj style (transition: all .8s ease-out;)
            backgroundCanvas.style.backgroundImage = "url('"+e.target.parentNode.href+"')";
            backgroundCanvas.style.inset = "0 auto auto 0";
            backgroundCanvas.style.width = "100%";
            backgroundCanvas.style.height = "100%";
        })
    })
</script>

Przykłady

Panorama Krakowa

Kraków, Polska Zdjęcie Dawida Łabno na Unsplash

W powiększeniu to co najlepsze

Pizza w warszawskim lokalu Zdjęcie Zuza Reinhard na Unsplash

Stadion Narodowy Warszawa

Wersja powiększenia z animacją w trakcie ładowania obrazka. Przy szybkim łączu lub małym pliku animacja jest niewidoczna. Poniżej animowany svg, który ją generuje.

Obrotowa ćwiartka na obręczy
Animacja wyświetlana w trakcie ładowania obrazka

Efekt ładowania obrazka uzyskuje się wykorzystując Image API. Przed wyświetleniem powiększenia tworzymy zmienną na obrazek, ładujemy plik do pamięci i w trakcie pobierania wyświetlamy animowany SVG. Po załadowaniu obrazka przeglądarka wywołuje obsługę zdarzenia „onload” z funkcją wyświetlającą powiększenie. Szczegóły w komentarzu kodu javascript.

Stadion Narodowy, Warszawa Obraz Henryk Niestrój z Pixabay

HTML, CSS, Javascript
    
<style>
.u-BlowUpImgPreload:hover {
    cursor: zoom-in;
}    
</style>
<script>
    document.addEventListener("DOMContentLoaded", function() {
        var backgroundCanvas = document.createElement("div");
        backgroundCanvas.style.cssText = "position: fixed; top: 50%; left: 50%; width: 0; height: 0; z-index: 2; \
        background: rgba(0,0,0,0.9) none 50% 50%/contain no-repeat; transition: all .8s ease-out; cursor: zoom-out;";
        document.body.appendChild(backgroundCanvas);
        // Tło dla animacji podczas ładowania obrazka
        var preloaderBackgroundCanvas = document.createElement("div");
        // Style
        preloaderBackgroundCanvas.style.cssText = "position: fixed; top: 50%; left: 50%; width: 15vmin; height: 15vmin; \
        background-repeat: no-repeat; background-position: center; background-size: 100%; z-index: 1; display: none;";
        // Animowany svg jako tło zdefiniowany w kodzie żeby nie było problemów z opóźnieniem przy wczytaniu pliku. Przy tak małej wadze istotność pamięci podręczniej znikoma.
        preloaderBackgroundCanvas.style.backgroundImage = "url('" + 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" version="1.1" viewBox="0 0 40 40"> \
        <title>Obrotowa ćwiartka na obręczy</title> \
        <circle cx="20" cy="20" r="16" fill="none" stroke="%23ee4e19" stroke-opacity=".2" stroke-width="5"/> \
        <path d="m1.39 20h4.97c0-8.56 7.05-13.6 13.6-13.6v-5.03c-9.99 0-18.6 8.33-18.6 18.6z" fill="%23ee4e19"> \
            <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 20 20" to="360 20 20" dur="0.6s" repeatCount="indefinite"/> \
        </path></svg>' + "')";
        document.body.appendChild(preloaderBackgroundCanvas);
        // Pełna wersja obrazka
        var fullPicture = new Image();
        backgroundCanvas.onclick = function() { 
            backgroundCanvas.style.top = "50%";
            backgroundCanvas.style.left = "50%";
            backgroundCanvas.style.width = "0";
            backgroundCanvas.style.height = "0";
        };
        var zoomInImgLinks = document.getElementsByClassName("u-BlowUpImgPreload");
        for(var i=0; i<zoomInImgLinks.length; ++i) zoomInImgLinks[i].addEventListener("click", function(e) {
            e.preventDefault();
            // Po załadowaniu obrazka do pamięci wywołanie zdarzenia z funkcją powiększenia.
            fullPicture.onload = function() {
                preloaderBackgroundCanvas.style.display = "none";
                backgroundCanvas.style.backgroundImage = "url(" + fullPicture.src + ")";
                backgroundCanvas.style.top = "0";
                backgroundCanvas.style.left = "0";
                backgroundCanvas.style.width = "100%";
                backgroundCanvas.style.height = "100%";
            }
            // Przypisanie adresu pełnej wersji zdjęcia zawsze wywołuje zdarzenie "onload", nawet jak jest identyczny (wielokrotne kliknięcie)
            // Jak w pamięci - wywołuje "onload". Jak nowy - rozpoczyna pobieranie.
            fullPicture.src = e.target.parentNode.href;
            // Wyświetlenie animacji w trakcie pobierania.
            // Jeśli obraz powiększenia w pamięci tylko krótkie błyśnięcie - można wyeliminować dodatkowymi warunkami - pozostawione dla przejrzystości kodu.
            preloaderBackgroundCanvas.style.display = "block";
        })
    })
</script>
<!-- HTML -->
<a class="u-BlowUpImgPreload" href="img/stadion-1398391_1920.jpg">
    <img src="img/stadion-1398391_640.jpg" width="640" height="462" alt="Stadion Narodowy, Warszawa">
</a>
<!-- HTML -->
    

Animowane umilacze oczekiwania na załadowanie obrazka

Kilka przykładowych animowanych obrazów (preloader) SVG wyświetlanych odwiedzającemu w trakcie pobierania powiększania. Po aktualizacjach z dnia i kolory w SVG zdefiniowane jako zmienne CSS (custom properties) i reagują prawidłowo na zmianę trybu wyświetlania.

Obrotowa ćwiartka na obręczy Obracający się półokrąg Kręcące się promienie Wirujące blaknące okręgi Zamykający się obwód koła 8 wirujących kawałków okręgu 3 skracające się pionowe słupki Rozchodzące się kręgi Zmieniający wielkość obrotowy kawałek obręczy Wirujące po okręgu kule

Warianty wyświetlania powiększenia

Uśmiechnięte oczy

Uśmiechnięta dziewczyna Zdjęcie Michael Dam na Unsplash

HTML, CSS, Javascript
    
<style>
.u-ShutterUpDown:hover {
    cursor: zoom-in;
}    
</style>
<script>
    document.addEventListener("DOMContentLoaded", function() {
        var backgroundCanvas = document.createElement("div");
        backgroundCanvas.style.cssText = "position: fixed; top: 50%; left: 0; width: 100%; height: 0; z-index: 1; background: rgba(0,0,0,0.9) none center/auto 100vmin no-repeat; transition: all .8s ease-out; cursor: zoom-out;";
        document.body.appendChild(backgroundCanvas);
        backgroundCanvas.onclick = function() { 
            backgroundCanvas.style.top = "50%";
            backgroundCanvas.style.left = "0";
            backgroundCanvas.style.width = "100%";
            backgroundCanvas.style.height = "0";
        };
        var zoomInImgLinks = document.getElementsByClassName("u-ShutterUpDown");
        for(var i=0; i<zoomInImgLinks.length; ++i) zoomInImgLinks[i].addEventListener("click", function(e) {
            e.preventDefault();
            backgroundCanvas.style.backgroundImage = "url('"+e.target.parentNode.href+"')";
            backgroundCanvas.style.top = "0";
            backgroundCanvas.style.left = "0";
            backgroundCanvas.style.width = "100%";
            backgroundCanvas.style.height = "100%";
        })
    })
</script>
<!-- HTML -->
<a class="u-ShutterUpDown" href="img/michael-dam-mEZ3PoFGs_k-unsplash.jpg">
    <img src="img/michael-dam-mEZ3PoFGs_k-unsplash-min.jpg" alt="Uśmiechnięta dziewczyna">
</a>
<!-- HTML -->
    

Przepis na ciasteczka

W powiększeniu pokaz slajdów + przepis. Zmiany zdjęć za pomocą animowanego png (apng). Przy wyłączonym javascript przepis wyświetla się pod miniaturką.

Przygotowanie ciasteczek Zdjęcie i wykonanie Dorota

HTML, CSS, Javascript
    
<style>
.u-DrawTheCurtains:hover {
    cursor: zoom-in;
}    
</style>
<script>
    document.addEventListener("DOMContentLoaded", function() {
        var backgroundCanvas = document.createElement("div");
        backgroundCanvas.style.cssText = "position: fixed; top: 0; left: 50%; width: 0; height: 100%; overflow: hidden; text-align: center; z-index: 1; background: rgba(255,255,255,0.95) none center/auto 100vmin no-repeat; transition: all .8s ease-out; cursor: zoom-out;";
        backgroundCanvas.innerHTML = document.getElementById("muffinRecipeDetails").innerHTML;//Dodanie html z noscript
        document.body.appendChild(backgroundCanvas);
        backgroundCanvas.onclick = function() { 
            backgroundCanvas.style.top = "0";
            backgroundCanvas.style.left = "50%";
            backgroundCanvas.style.width = "0";
            backgroundCanvas.style.height = "100%";
        };
        var zoomInImgLinks = document.getElementsByClassName("u-DrawTheCurtains");
        for(var i=0; i<zoomInImgLinks.length; ++i) zoomInImgLinks[i].addEventListener("click", function(e) {
            e.preventDefault();
            backgroundCanvas.style.backgroundImage = "url('"+e.target.parentNode.href+"')";
            backgroundCanvas.style.top = "0";
            backgroundCanvas.style.left = "0";
            backgroundCanvas.style.width = "100%";
            backgroundCanvas.style.height = "100%";
        })
    })
</script>
<!-- HTML -->
<a class="u-DrawTheCurtains" href="img/muffins-animated.png">
    <img src="img/muffins-composition-min.png" width="384" height="288" alt="Przygotowanie ciasteczek">
</a>
<span style="font-size: .8em; display: block;">Zdjęcie i wykonanie Dorota</span>
<noscript id="muffinRecipeDetails">
    <h3>Muffiny z mąki gryczanej i kukurydzianej</h3>
    <ul style="display: inline-block; text-align:left; color: #000;">
        <li>mąka gryczana - 120 gram</li>
        <li>mąka kukurydziana - 80 gram</li>
        <li>skórka cytrynowa</li>
        <li>sok z połowy cytryny</li>
        <li>olej - 100 ml</li>
        <li>mleko - 100 ml</li>
        <li>jajka - 2 sztuki</li>
        <li>Rozbij jajka z mlekiem</li>
        <li>Wlej mieszankę do mąki i zmiksuj</li>
        <li>Wlej ciasto do papilotek</li>
        <li>Piecz aż będą złote i popękane</li>
    </ul>
</noscript>
<!-- HTML -->
    

Użyj wyobraźni lub kliknij

Dziewczyna w czarnych pończochach Zdjęcie Jan Szwagrzyk na Unsplash

HTML, CSS, Javascript
    
<style>
    .u-CourtainLeftSlowImg:hover {
        cursor: zoom-in;
    }    
</style>
<script>
    document.addEventListener("DOMContentLoaded", function() {
        var backgroundCanvas = document.createElement("div");
        backgroundCanvas.style.cssText = "position: fixed; top: 0; left: 100%; width: 0; height: 100%; z-index: 1; background: rgba(0,0,0,0.9) none center/auto 100vmin no-repeat; transition: all 6s ease-out; cursor: zoom-out;";
        document.body.appendChild(backgroundCanvas);
        backgroundCanvas.onclick = function() { 
            backgroundCanvas.style.top = "0";
            backgroundCanvas.style.left = "100%";
            backgroundCanvas.style.width = "0";
            backgroundCanvas.style.height = "100%";
        };
        var zoomInImgLinks = document.getElementsByClassName("u-CourtainLeftSlowImg");
        for(var i=0; i<zoomInImgLinks.length; ++i) zoomInImgLinks[i].addEventListener("click", function(e) {
            e.preventDefault();
            backgroundCanvas.style.backgroundImage = "url('"+e.target.parentNode.href+"')";
            backgroundCanvas.style.top = "0";
            backgroundCanvas.style.left = "0";
            backgroundCanvas.style.width = "100%";
            backgroundCanvas.style.height = "100%";
        })
    })
</script>
<!-- HTML -->
<a class="u-CourtainLeftSlowImg" href="img/jan-szwagrzyk-0YbvWz-Wxqw-unsplash.jpg">
    <img src="img/jan-szwagrzyk-0YbvWz-Wxqw-unsplash-min.jpg" width="400" height="495" alt="Dziewczyna w czarnych pończochach">
</a>
<!-- HTML -->