Prosta galeria zdjęć z wykorzystaniem jQuery

Artykuł dodany: 06 listopada 2016. Ostatnia modyfikacja: 06 listopada 2016.

Stopień trudności (1 - dla początkujących, 5 - dla ekspertów): 2

Wyświetlanie zdjęć na stronie w postaci galerii jest równie popularne, co osadzanie formularzy. Wtyczek, w szczególności do biblioteki jQuery, występuje tyle co wody w rzece. Biblioteki te mogą mieć jednak kilka wad. Mogą nie wspierać aktualnej wersji jQuery, mogą kolidować z innymi elementami występującymi już na stronie, ze względu na poziom skomplikowania mogą zawierać dużo nadmiarowego kodu – co za tym idzie, ich rozmiar zazwyczaj zaczyna się od ~10kB po skompresowaniu. Zdecydowanie za dużo aby wyświetlić kilka zdjęć z miniaturkami. Z drugiej strony, stworzenie kodu odpowiedzialnego za działanie galerii to raptem kilka linijek w JS. Aby rozpocząć, niezbędna będzie wiedza z zakresu obsługi biblioteki jQuery (w szczególności opisywane wcześniej zdarzenia i metoda on()), podstawowa wiedza o elementach HTML i niewielka ilość CSS do sformatowania wyglądu.

Nasza galeria będzie musiała spełniać następujące warunki:

- zdjęcie w pełnym rozmiarze ma się wyświetlać także po wyłączeniu JavaScriptu
- możliwe ma być osadzeniu kilku galerii jednocześnie na stronie i mają ze sobą nie kolidować
- zdjęcia w pełnym rozmiarze powinny zawierać opcjonalny opis

Przygotowanie HTML

Obecnie raczej wszystkie strony tworzy się przy pomocy HTML5, zatem i nasza galeria będzie napisana w tej technologii. Podstawowa struktura całego dokumentu powinna przyjąć postać:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"/>
    <meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport"/>
    <title>Galeria zdjęć</title>
    <style type="text/css"><!-- style CSS naszej galerii --></style>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script type="text/javascript"><!-- kod JS --></script>
</head>
<body>
    <main>
    <!-- zawartość galerii -->
    </main>
</body>
</html>

Podstawowym kodowaniem naszej strony jest UTF-8 (jeśli nie wiesz o co chodzi zapoznaj się z poprzednim artykułem). Korzystając z edytora warto pamiętać, aby plik zapisać jako UTF-8 bez BOM. Zarówno style i jak kod JS dla ułatwienia zamieszczę w treści dokumentu, jednak najlepiej aby w środowisku produkcyjnym znalazły się one w oddzielnych plikach. Dzięki temu ich edycja jest łatwiejsza a też przeglądarka pobiera taki plik z cache, redukując tym samym wielkość pobieranych za każdym razem danych. Możemy też połączyć kod z już istniejącymi plikami. Dodatkowo osadziłem bibliotekę jQuery która jest niezbędna do prawidłowego działania galerii i zapewne występuje już na naszej stronie. Pamiętaj aby nie wczytywać plików biblioteki podwójnie. Jeśli masz ją już osadzoną pomiń ten wpis.

Wreszcie kod naszej galerii (dodany wewnątrz elementu `main`):

<div class="gallery">
    <div class="gallery-full">
        <h1>Tytuł pierwszego zdjęcia</h1>
        <img src="obrazki/full/1.jpg"/>
    </div>

    <ul class="gallery-thumb">
        <li><a href="obrazki/full/1.jpg" title="Opis zdjęcia 1"><img src="obrazki/thumb/1.jpg"/></a></li>
        <li><a href="obrazki/full/2.jpg"><img src="obrazki/thumb/2.jpg"/></a></li>
        <li><a href="obrazki/full/3.jpg" title="Opis zdjęcia 3"><img src="obrazki/thumb/3.jpg"/></a></li>
        <li><a href="obrazki/full/4.jpg"><img src="obrazki/thumb/4.jpg"/></a></li>
    </ul>
</div>

Galeria składa się z dwóch sekcji. Element o klasie `gallery-full` zawiera opis zdjęcia oraz samo zdjęcie w pełnym rozmiarze. Domyślnie możemy tu podstawić dowolne zdjęcie, niekoniecznie element naszej galerii. Lista `gallery-thumb` zawiera linki wraz ze zdjęciami miniaturek. Wewnątrz atrybutu `title` umieszczony jest opis zdjęcia, który zostanie skopiowany do elementu `h1`. Oba elementy zamknięte są w kontenerze ogólnym `gallery`.

Zdjęcia postanowiłem trzymać w dwóch folderach: `full` – zdjęcie w pełnym rozmiarze, `thumb` – przygotowana wcześniej miniaturka.

Formatowanie przy użyciu CSS

Zapewne każdy z Was będzie chciał sformatować galerię odpowiednio do własnych potrzeb dlatego kod jest bardzo ogólny. Umieszczamy go w sekcji `style` lub w osobnym pliku.

.gallery .gallery-full {
    position: relative;
    text-align: left;
    margin-bottom: .5em;
}
.gallery .gallery-full h1 {
    position: absolute;
    top: 0;
    left: 0;
    background: rgba(0, 0, 0, .5);
    color: #fff;
    font-size: 1.3rem;
    padding: 2px 5px;
}
.gallery .gallery-full img {
    display: block;
    height: auto;
    /*max-width: 100%;*/
    max-width: 800px;
}
.gallery ul.gallery-thumb {
    margin: 0;
    padding: 0;
}
.gallery ul.gallery-thumb li {
    display: inline-block;
}
.gallery ul.gallery-thumb li img {
    height: auto;
    width: 150px;
    vertical-align: middle;
}
.gallery ul.gallery-thumb li img.active {
    opacity: .65;
}

Kontener z pełnym zdjęciem pozycjonujemy relatywnie co sprawia, że umieszczony niżej opis zdjęcia znajdzie się bezpośrednio na ustalonej wysokości względem niego. W praktyce zostanie spozycjonowany na zdjęciu. Opisowi dajemy też czarne tło z połowiczną przezroczystością i białymi literami co powinno sprawić, iż będzie widoczny na każdym zdjęciu. Zdjęcie otrzymuje testowo 800px szerokości, jednak jeżeli chcemy aby skalowało się płynnie w zależności od rozdzielczości, powinniśmy odkomentować zapis `max-width: 100%;`. Miniaturki ustawiamy obok siebie za pomocą `display: inline-block` i dla pewności ograniczamy ich szerokość do 150px (wysokość dopasuje się automatycznie). Aktywnym (klikniętym) miniaturkom nadajemy lekką przezroczystość aby je wyróżnić.

Podmiana zdjęć za pomocą jQuery

Pora na najciekawsze czyli właściwy kod odpowiedzialny za wyświetlanie zdjęć w galerii. Wygląda on następująco:

// linia odpowiada za przetworzenie kodu w momencie, gdy HTML będzie gotowy (wczytany)
$(function() {
    // nasłuchujemy na kliknięcie w element `a`
    // wykorzystana jest delegacja zdarzeń opisana wcześniej
    $('.gallery').on('click', 'ul.gallery-thumb a', function(e) {
        // linki i elementy formularza typu submit albo button mają domyślne akcje
        // preventDefault() sprawia że nie zostaną one wykonane
        // w tym wypadku nie nastąpi przekierowanie na stronę pełnego obrazka
        // zobacz również w konsoli co zwróci kod console.log(e);
        // warto przyjrzeć się właściwościom zdarzenia
        e.preventDefault();

        //deklaracja pomocniczych zmiennych
        // e.delegateTarget oznacza nasłuchującego rodzica - element .gallery
        var galleryFull = $(e.delegateTarget).children('.gallery-full'),
            imageSrc    = $(this).attr('href'),
            // w przypadku gdyby zdjęcie nie miało ustawionego tytułu, definiujemy własny
            imageTitle  = $(this).attr('title') || 'Domyślny opis zdjęcia';

        // ustawiamy atrybuty zdjecia głównego na bazie miniaturek
        galleryFull.children('img').attr(
            {
                'src': imageSrc,
                'alt': imageTitle
            }
        );
        // ustawiamy tytuł zdjecia odczytany z atrybutu `title`
        galleryFull.children('h1').html(imageTitle);

        // usuwamy klasę `active` dla wszystkich miniaturek 
        // aby w linii poniżej dodać ją do klikniętego zdjęcia
        $(this).parents('ul.gallery-thumb').find('img').removeClass('active');
        $(this).children('img').addClass('active');
    });
});

Pomijając komentarze oraz ładne formatowanie całość zamyka się w 7 liniach kodu.

Nasza galeria będzie działać jednak jest jeszcze jeden problem. Wczytanie zdjęcia może chwilę potrwać a użytkownik nie ma żadnej o tym informacji. Dla większych zdjęć może się wręcz wydawać że coś jest nie tak. Aby to poprawić musimy, po kliknięciu w miniaturę, wyświetlić odpowiedni komunikat w miejscu normalnego opisu. Po załadowaniu pliku w całości komunikat podmienimy na właściwy opis.

// komunikat może być dostępny w zmiennej od razu
var message = 'Wczytywanie zdjęcia...';
$(function() {
    $('.gallery').on('click', 'ul.gallery-thumb a', function(e) {
        e.preventDefault();

        var galleryFull = $(e.delegateTarget).children('.gallery-full'),
            imageSrc    = $(this).attr('href'),
            imageTitle  = $(this).attr('title') || 'Domyślny opis zdjęcia';
        galleryFull.children('img').attr(
            {
                'src': imageSrc,
                'alt': imageTitle
            }
        );
        // zamiast tytułu wstawiamy nasz komunikat
        galleryFull.children('h1').html(message);

        $(this).parents('ul.gallery-thumb').find('img').removeClass('active');
        $(this).children('img').addClass('active');
    });
    // po pełnym załadowaniu zdjęcia podmieniamy komunikat oczekiwania na tytuł
    $('.gallery .gallery-full img').on('load', function() {
        $(this).prev().html($(this).attr('alt'));
    });
});

Moglibyśmy również do naszego zdjęcia przypiąć zdarzenie `error` które zostało by uruchomione w przypadku jakiegoś błędu podczas wczytywania. Tutaj pominę ten fragment.
Jeszcze jedna ważna informacja. Na zdarzeniach `error`, `load` oraz `scroll` nie ma możliwości używania delegacji dlatego zdarzenie `load` dla zdjęcia zostało podpięte oddzielnie.

Działający przykład

Kod wykonywany w przeglądarce można obejrzeć na stronie demonstracyjnej.

Komentarze

Nie ma jeszcze żadnych komentarzy do wyświetlenia. Może chcesz zostać pierwszą osobą która podzieli się swoją opinią?

Dodaj komentarz

*
Nazwa zostanie wyświetlona wraz z komentarzem. Możesz też utworzyć nowe konto w serwisie, dzięki czemu uzyskasz dodatkową funkcjonalność.
*
Akceptowana jest ograniczona składnia Textile. Wszystkie tagi HTML zostaną usunięte.