Okładka artykułu Tworzymy stronę z pionową nawigacją — Z płynnym przechodzeniem między sekcjami
Poradniki

Tworzymy stronę z pionową nawigacją

Z płynnym przechodzeniem między sekcjami

Zdjęcie autora Hubert Tulibacki
0

W dzisiejszym artykule pokażę Wam, jak prosto przygotować przyciski do pionowej nawigacji po Waszej stronie internetowej. Taka nawigacja jest jednym z podstawowych elementów stron typu „one page website”.

Podstawowe założenia naszej nawigacji, to płynne przechodzenie z jednego elementu do drugiego oraz możliwość tworzenia odnośników do poszczególnych elementów na stronie. A więc zaczynajmy!

Na początek, przygotowałem sobie krótki kod HTML strony, na której przedstawię Wam działanie skryptu. Kod ten zawiera sześć sekcji, po których będziemy nawigować. W moim przykładzie, te sekcje są puste, ale Wy możecie sobie wypełnić je dowolną treścią strony.

<!DOCTYPE html>
<html dir="ltr" lang="pl">
    <head>
        <meta charset="UTF-8" />

        <title>Pionowa nawigacja</title>
        <meta name="description" content="" />
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />

        <link rel="stylesheet" href="css/style.css" />
    </head>
    <body>
        <section id="first" class="anchor">
            
        </section>
        
        <section id="second" class="anchor">
            
        </section>
        
        <section id="third" class="anchor">
            
        </section>
        
        <section id="foruth" class="anchor">
            
        </section>
        
        <section id="fifth" class="anchor">
            
        </section>
        
        <section id="sixth" class="anchor">
            
        </section>
        
        <nav id="sidenav">
            <ul>
                <li><a href="#first">1</a></li>
                <li><a href="#second">2</a></li>
                <li><a href="#third">3</a></li>
                <li><a href="#foruth">4</a></li>
                <li><a href="#fifth">5</a></li>
                <li><a href="#sixth">6</a></li>
            </ul>
        </nav>
        
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
        <script src="js/tools.js"></script>
    </body>
</html>

Kolejnym etapem jest stworzenie przykładowego pliku CSS, w którym nadałem prosty wygląd sekcjom, żeby się od siebie odróżniały podczas przewijania strony.

html, body {
    margin: 0px;
    padding: 0px;
}

section {
    height: 800px;
}

#first {
    background: #3f0b1b url('../img/1.png') scroll no-repeat center center;
}

#second {
    background: #7a1631 url('../img/2.png') scroll no-repeat center center;
}

#third {
    background: #cf423c url('../img/3.png') scroll no-repeat center center;
}

#foruth {
    background: #fc7d49 url('../img/4.png') scroll no-repeat center center;
}

#fifth {
    background: #ffd462 url('../img/5.png') scroll no-repeat center center;
}

#sixth {
    background: #ffedbe url('../img/6.png') scroll no-repeat center center;
    height: 1200px;
}

Wielkość sekcji nie ma znaczenia. Ważne jest jedynie, aby ostatnia była nieco wyższa niż okno przeglądarki użytkownika, który będzie przeglądał stronę. Jeśli ten warunek nie zostanie spełniony, oznaczanie aktywnego elementu na nawigacji nie będzie działało poprawnie dla ostatniej sekcji.

Nadszedł czas, aby nadać wygląd przyciskom, którymi będziemy nawigowali. Umieszcza się je z reguły po prawej stronie, dlatego też zrobiłem podobnie.

#sidenav {
    position: fixed;
    top: 50%;
    right: 53px;
    height: 216px;
    margin-top: -108px;
}

#sidenav ul {
    list-style-type: none;
    margin: 0px;
    padding: 0px;
}

#sidenav li {
    width: 16px;
    height: 16px;
    margin-bottom: 20px;
}

#sidenav li a {
    display: block;
    width: 16px;
    height: 16px;
    text-indent: 11985px;
    background: transparent url('../img/nav.png') scroll no-repeat top center;
}

#sidenav li a:hover, #sidenav li a.active {
    background-position: bottom center;
}

Nawigacji nadajemy pozycję fixed, aby trzymała się okna przeglądarki. Wysokość jej powinna być taka, jak suma wysokości każdego elementu nawigacji. U mnie to 36 px (16 px wysokości plus 20 px marginesu), co pomnożone przez sześć, daje właśnie 216 px. Odpowiednie użycie marginesów sprawia, że element wyświetla się zawsze dokładnie na środku okna przeglądarki. W elemencie a pozbywamy się tekstu za pomocą text-indent, aby został sam obrazek tła. Identyczne kółka, jakie zrobiłem przy użyciu obrazków, można zrobić za pomocą CSS. Jednak ja skorzystałem z gotowego kodu, który stworzyłem wcześniej dla jednego z projektów.

JavaScript

Do napisania skryptu, który będzie płynnie przesuwał naszą stronę, wykorzystuję framework jQuery, toteż można go zobaczyć załączonego na samym dole kodu HTML. W tym samym miejscu do dokumentu dołączony jest plik tools.js, w którym umieścimy nasz skrypt.

Zaczniemy od napisania krótkiej funkcji, która po odpaleniu, przesunie nam suwak strony do określonego miejsca. Tym miejscem będzie wybrany element, w naszym wypadku – jedna z sekcji. Oto kod:

function simpleScrollTo(element, speed) {
    $('html:not(:animated), body:not(:animated)').animate({scrollTop: $(element).offset().top}, speed, function() {
        document.location.hash = $(element).attr('id');
    });
}

Jak widać, po wywołaniu funkcji, strona zaczyna się przewijać do elementu podanego przekazanego w zmiennej element (o ile wcześniej animacja nie została wywołana – stąd selektor not(:animated)) z prędkością podaną w parametrze speed (wyrażoną w milisekundach). Po zakończeniu animacji, hash strony jest zmieniany na aktualny. Więcej o tym później. Teraz musimy tę funkcję wywołać, a robimy to za pomocą przypisania zdarzenia “po kliknięciu” do każdego z przycisków nawigacji. Oto kod:

$(function() {
    $('#sidenav a').click(function (e) {
        e.preventDefault();
        
        simpleScrollTo($(this).attr('href'), 500);
    });
});

Ten prosty kawałek kodu sprawia, że strona zostaje przewinięta do elementu, który posiada identyfikator tożsamy z tym, jaki podaliśmy w atrybucie href przycisku. W tym miejscu określamy również prędkość przewijania, ja ustaliłem ją na pół sekundy.

Kolejnym krokiem będzie aktualizowanie hashu strony na bieżąco, aby użytkownik w każdej chwili mógł skopiować link strony (albo dodać go do zakładek) w ten sposób, aby po wejściu strona przewijała się automatycznie do aktualnego elementu. Przy okazji, w nawigacji po prawej stronie, również oznaczymy, który element aktualnie przeglądamy. Kod, który to umożliwia, przedstawiony jest na listingu poniżej:

$(window).scroll(function() {
    var ds = $(document).scrollTop();
    
    if (ds == 0) {
        $('#sidenav a').removeClass('active');
        $('#sidenav a[href=#' + $('.anchor').eq(0).attr('id') + ']').addClass('active');
        
        return false;
    }
    
    $('.anchor').each(function() {
        var $this = $(this), offset = Math.round($this.offset().top), height = $this.outerHeight() + offset;
        
        if (offset <= ds && height > ds) {
            $('#sidenav a').removeClass('active');
            $('#sidenav a[href=#' + $this.attr('id') + ']').addClass('active');
            if (document.location.hash != '#' + $this.attr('id')) {
                var cds = $(document).scrollTop();
                document.location.hash = $this.attr('id');
                $(document).scrollTop(cds);
            }
            
            return false;
        }
        
        return true;
    });
    
    return true;
});

Pierwsza instrukcja warunkowa sprawdza, czy aby przypadkiem nie znajdujemy się na samej górze strony. Jeśli tak – wiadomo, że aktywny musi być pierwszy element. Następnie iterujemy po wszystkich elementach posiadających klasę anchor (tą klasę nadajemy wszystkim sekcjom, do których chcemy przewijać naszą stronę) i staramy się ustalić, który element aktualnie przeglądamy. Jeżeli odkryjemy, że aktualny element się zmienił, zmieniamy również hash i aktywny element w menu.

Teraz podobną operację musimy zastosować, kiedy użytkownik wchodzi na stronę z podanym hashem. Wtedy musimy ustawić aktualną pozycję w menu. Robi to poniższy kod. Jest to uproszczona wersja kodu służącego do wykrywania pozycji podczas przewijania.

var ds = $(window).scrollTop();
if (ds == 0) {
    $('#sidenav a').removeClass('active');
    $('#sidenav a[href=#' + $('.anchor').eq(0).attr('id') + ']').addClass('active');
} else {
    $('.anchor').each(function() {
        var $this = $(this), offset = Math.round($this.offset().top), height = $this.outerHeight() + offset;

        if (offset <= ds && height > ds) {
            $('#sidenav a').removeClass('active');
            $('#sidenav a[href=#' + $this.attr('id') + ']').addClass('active');

            return false;
        }

        return true;
    });
}

Ostatnim etapem jest płynne przewinięcie strony do odpowiedniego miejsca, jeśli użytkownik wejdzie na nią z hashem.

if (document.location.hash != '') {
    var el = $(document.location.hash);
    if (el.length > 0) {
        $(window).scrollTop(0);
        $(window).load(function() {
            simpleScrollTo('#' + el.attr('id'), 500);
        });
    }
}

Sprawdzamy najpierw, czy adres dokumentu ma hash, jeśli tak, próbujemy znaleźć taki element na stronie. Jeśli jest, przewijamy do niego, używając wcześniej już napisanej funkcji.

Kompletny kod

Kompletny kod w pliku tools.js powinien wyglądać tak:

$(function() {
    $('#sidenav a').click(function (e) {
        e.preventDefault();
        
        simpleScrollTo($(this).attr('href'), 500);
    });
    
    $(window).scroll(function() {
        var ds = $(document).scrollTop();
        
        if (ds == 0) {
            $('#sidenav a').removeClass('active');
            $('#sidenav a[href=#' + $('.anchor').eq(0).attr('id') + ']').addClass('active');
            
            return false;
        }
        
        $('.anchor').each(function() {
            var $this = $(this), offset = Math.round($this.offset().top), height = $this.outerHeight() + offset;
            
            if (offset <= ds && height > ds) {
                $('#sidenav a').removeClass('active');
                $('#sidenav a[href=#' + $this.attr('id') + ']').addClass('active');
                if (document.location.hash != '#' + $this.attr('id')) {
                    var cds = $(document).scrollTop();
                    document.location.hash = $this.attr('id');
                    $(document).scrollTop(cds);
                }
                
                return false;
            }
            
            return true;
        });
        
        return true;
    });
    
    var ds = $(window).scrollTop();
    if (ds == 0) {
        $('#sidenav a').removeClass('active');
        $('#sidenav a[href=#' + $('.anchor').eq(0).attr('id') + ']').addClass('active');
    } else {
        $('.anchor').each(function() {
            var $this = $(this), offset = Math.round($this.offset().top), height = $this.outerHeight() + offset;

            if (offset <= ds && height > ds) {
                $('#sidenav a').removeClass('active');
                $('#sidenav a[href=#' + $this.attr('id') + ']').addClass('active');

                return false;
            }

            return true;
        });
    }
    
    if (document.location.hash != '') {
        var el = $(document.location.hash);
        if (el.length > 0) {
            $(window).scrollTop(0);
            $(window).load(function() {
                simpleScrollTo('#' + el.attr('id'), 1000);
            });
        }
    }
});

function simpleScrollTo(element, speed) {
    $('html:not(:animated), body:not(:animated)').animate({scrollTop: $(element).offset().top}, speed, function() {
        document.location.hash = $(element).attr('id');
    });
}

Mam nadzieję, że ten artykuł pomoże Wam w tworzeniu jednostronicowych witryn internetowych z pionową nawigacją. Działanie powyższego skryptu możecie zobaczyć po kliknięciu na przycisk “zobacz demo”. Po kliknięciu tutaj można zobaczyć, jak skrypt zachowuje się, gdy wchodzimy na stronę z podanym hashem. Jeśli macie jakieś pytania lub propozycje na ulepszenie kodu, nie wahajcie się napisać op tym w komentarzu.

To może Cię zainteresować