„Prawdziwe” przejścia stron bez ingerencji w back-end

„Prawdziwe” przejścia stron bez ingerencji w back-end

Tytuł tego wpisu być może nie brzmi prosto i pewnie zastanawiasz się co mam na myśli pisząc „prawdziwe”. Otóż wiele przykładów udostępnianych w sieci, pokazujących super ładne i płynne przejścia stron, jest nieprzydatnych. Często zdarza się, że treść kolejnych podstron nie jest pobierana na żądanie użytkownika a zmiana adresu URL ogranicza się do podmiany hash-a. Spróbujmy zrobić to inaczej – tak prawdziwie.

Schemat działania

Podstawowe sprawy, na których mi zależy to podmiana URL, zachowanie funkcjonalności przycisku „back” w przeglądarce oraz możliwość animacji w trakcie podmiany treści. Zależy mi również by wszystko działo się niezależnie od użytego back-endu – wyłącznie po stronie klienta. Aby coś takiego zrealizować idealnie nada się JavaScript a także jest asynchroniczne możliwości. Plan działania, który pozwoli uzyskać założony efekt będzie wyglądał następująco:

  1. Wykrycie żądania zmiany adresu.
  2. Pokazanie ikony loadera.
  3. Wysłanie zapytania AJAX w celu pobrania nowej treści.
  4. Wstawienie nowej treści do widoku i aktualizacja URL.
  5. Animacja przejścia i ukrycie ikony loadera.
  6. Usunięcie kodu poprzedniej podstrony.

Tak się składa, że wszystko to co potrzebujemy realizuje plugin do jQuery smoothState. Jak pisze sam autor, głównym zadaniem tego pluginu jest umożliwienie animowanego przejścia między stronami bez żadnej ingerencji w back-end. Ponieważ większość realizowanych przeze mnie projektów stoi na WordPressie, smoothState wydaje się być świetnym rozwiązaniem.

Jak zrobić przejścia stron?

1. HTML

Zacznijmy od tego, że smoothState wymaga stworzenia pewnego szkieletu strony. Każda z podstron (a właście treść, która będzie ładowana) powinna być osadzona w elemencie o niezmiennym ID – moim przypadku jest to #page. Belkę nawigacji wyrzucamy poza #page, ponieważ ten element jest stały i nie chcemy aby kiedykolwiek znikał.

<nav class="main-nav">
   //linki do podstron
</nav>

<div class="page-container" id="page">
  <div class="page-container__animate page-container__reset">
     //treść podstrony
  </div>
</div>

Klasa __reset to klasa resetująca animację CSS i będzie usuwana gdy pojawi się nowa treść. Oznacza to, że w momencie załadowania nowej treści, element poddany zostanie animacji pojawiania się. To jest właściwie wszystko czego potrzebujemy od strony HTML-a.

2. jQuery

Kolejnym krokiem jest zainicjowanie smoothState oraz dodanie obsługi zdarzeń. Podstawowa inicjacja skryptu wygląda następująco:

var page = $("#page").smoothState({
    onStart: {
       duration: 0,
       render: function () {
          //żądanie zmiany podstrony
       }
    },
    onReady: {
       render: function ($container, $newContent) {
         //załadowano nowy HTML
       }
    }
}).data("smoothState");

Wtyczka smoothState posiada znacznie większe możliwości konfiguracji lecz na potrzeby tego demo możemy je pominąć. Samo doprowadzenie do sytuacji gdy przejścia stron zaczną wyglądać tak jak powinny, wymaga cierpliwości a nawet kilku prób i błędów.

W tym momencie powinniśmy zająć się właściwą podmianą HTML-a oraz przygotowaniem klas do animacji. Po pierwsze, w funkcji onStart pokazujemy ikonę loadera i przewijamy stronę na samą górę (nie chcemy czytać nowej podstrony od połowy):

render: function () {
   $(".page-loader").fadeIn(150); 
   $('html, body').animate({ 
      scrollTop: 0
   },300);
}

Po drugie, w onReady wstawiamy świeżo pobrany HTML do naszego #page:

onReady: {
   render: function ($container, $newContent) {
      //wstaw nowy HTML
      $container.append($newContent);  
   }
}

Celowo wykorzystałem tutaj append() gdyż nie chcę nadpisać starej treści – usunę ją później gdy zakończy się animacja. Animację załatwimy dwiema klasami. Pierwsza z nich (__out) pozbędzie się starej treści z widoku. Usunięcie drugiej klasy (__reset) pokaże nową treść a switch_nav_active() ustawi klasę dla aktualnego linku w belce nawigacji. Całość opakowana zostanie w setTimeout() by mieć pewność, że HTML został wstawiony już w odpowiednie miejsce.

onReady: {
   render: function ($container, $newContent) {
      //wstaw nowy HTML
      $container.append($newContent);  
      
      //rozpocznij animację
      setTimeout(function(){
        $(".page-container__animate").eq(0).addClass("page-container__out");
        $(".page-container__animate").eq(1).removeClass('page-container__reset');
        //ustaw active w belce nawigacji
        switch_nav_active(window.location.href);
      },100);
   }
}

Na koniec ukrywamy ikonę loadera i pozbywamy się starego HTML. Tu należy zadbać o dopasowanie odpowiedniego opóźnienia tak aby nie został on usunięty zbyt wcześnie (w trakcie animacji przejścia).

onReady: {
   render: function ($container, $newContent) {
      //wstaw nowy HTML
      $container.append($newContent);  
      
      //rozpocznij animację
      setTimeout(function(){
        $(".page-container__animate").eq(0).addClass("page-container__out");
        $(".page-container__animate").eq(1).removeClass('page-container__reset');
        //ustaw active w belce nawigacji
        switch_nav_active(window.location.href);
      },100);

      //usuń stary HTML i ukryj loader
      setTimeout(function(){
         $(".page-container__out").remove();
         $(".page-loader").fadeOut(150);
      },600);		
   }
}

Najważniejsze zadanie już za nami. Teraz należy obsłużyć linki z belki nawigacyjnej:

$(".main-nav a").on("click",function(e){
   e.preventDefault();
   page.load( $(this).attr("href") );
});

i przygotować funkcję switch_nav_avtive. Funkcja ta porównuje aktualny URL z atrybutami „href” przypisanymi w menu.

function switch_nav_active( pathname ){ 
   $(".main-nav li").removeClass("active");
   var $currentItem;
   $(".main-nav li").each(function(){
      var url = $(this).find("a").attr('href');
      if( pathname.search(url)!=-1 ) $currentItem = $(this);
   });
   $currentItem.addClass("active");
}

Ostatnia rzecz jaką musimy zrobić to usunąć klasę __out i ukryć loader w momencie pierwszego wejścia na stronę lub jej odświeżenia.

$(document).ready(function(){
   $(".page-loader").fadeOut(150);
   $(".page-container__animate").removeClass("page-container__reset");
});

To wszystko jeżeli chodzi o jQuery. Skrypt jest gotowy i powinien już działać. Pora zająć się animacją.

CSS

W każdym z trzech wariantów demo zasada jest taka sama: klasa __out do usunięcia starej treści; klasa __reset do pojawienia się nowej. Zaczynamy od zdefiniowania atrybutów odpowiedzialnych za prędkość animacji oraz funkcję easingu.

.demo__1 .page-container__animate {
   transition: -webkit-transform .45s cubic-bezier(.215, .61, .355, 1);
   transition: transform .45s cubic-bezier(.215, .61, .355, 1);
   -webkit-transform: translate(0, 0);
   transform: translate(0, 0);
}

Demo 1 wyrzuca starą treść w lewo i wprowadza nową z prawej strony. Zatem dla klasy __reset (nowa treść) wykorzystujemy transform:

.demo__1 .page-container__animate.page-container__reset {
   -webkit-transform: translate(100%, 0);
   transform: translate(100%, 0)
}

Dla starej treści definiujemy analogicznie klasę __out używając transform o przeciwnej wartości. Tutaj pojawia się jeden haczyk. Ponieważ w trakcie animacji mamy w kontenerze dwie podstrony, domyślnie ułożą się one jedna pod drugą. Aby uzyskać pożądany efekt slidera, musimy starej treści nadać position: absolute by pojawiła się ona na tej samej wysokości co nowa.

.demo__1 .page-container__animate.page-container__out {
   position: absolute;
   width: 100%;
   top: 0;
   left: 0;
   -webkit-transform: translate(-100%, 0);
   transform: translate(-100%, 0)
}

Voila! Jeżeli niczego nie spartoliłeś, powinieneś cieszyć oko płynną animacją przejścia stron. W razie problemów wykorzystaj kod dostępny w źródle (main.css oraz main.js).

Podsumowanie

W erze mody na aplikacje SPA (Single page application) istnieje wiele różnych rozwiązań tworzenia animowanych przejść strony. SmoothState świetnie sprawdza się przy klasycznych CMS-a opartych na PHP jak chociażby WordPress. Do tej pory postawiłem już kilka stron, które wykorzystują tę wtyczkę i jak na razie nie znalazłem prostszego i łatwiejszego w konfiguracji narzędzia. Mam nadzieję, że i wam się kiedyś przyda.


Popularne wpisy

Kodowanie

Responsywne menu — 3 sprawdzone rozwiązania

Responsywne menu — 3 sprawdzone rozwiązania

Czytaj to
Mixiny SCSS – czyli jak uprzyjemniam sobie pracę

Mixiny SCSS – czyli jak uprzyjemniam sobie pracę

Czytaj to

Felietony

Błędy początkujących webmasterów, których warto unikać

Błędy początkujących webmasterów, których warto unikać

Czytaj to
Dlaczego frameworki HTML często nie mają sensu?

Dlaczego frameworki HTML często nie mają sensu?

Czytaj to

Inspiracje

Zestaw prostych i ciekawych przycisków na stronę

Zestaw prostych i ciekawych przycisków na stronę

Czytaj to
Najlepsze strony, z których pobierzesz darmowe zdjęcia

Najlepsze strony, z których pobierzesz darmowe zdjęcia

Czytaj to

Newsletter

Maksymalnie raz w miesiącu dostaniesz powiadomienie o nowych wpisach.
Zapisz się do newslettera — ja nie śmiecę.

Ta strona wykorzystuje pliki cookies wyłącznie w celach statystycznych.