Jak stworzyć animowane hamburger menu – poradnik krok po kroku

Front-end 5 minut czytania

Chyba większość z nas zgodzi się, że tak zwane hamburger menu to często jedyny sensowny sposób na stworzenie nawigacji, która dobrze wygląda na urządzeniach mobilnych. Swoją drogą często spotykane jest też na wersjach desktopowych.

Dlatego w tym artykule chciałbym pokazać Ci w jaki sposób można utworzyć taki element jednocześnie dbając o jego wygląd oraz sposób działania!

Może zacznijmy od końca

Zanim zaczniemy tworzyć sam element, sprawdźmy jak to w ogóle ma wyglądać w efekcie końcowym:

See the Pen Hamburger menu by Robert Orliński (@ROrlilnski) on CodePen.

No fajne, wiadomo już jak całość działa, ale przejdźmy przez najważniejsze – proces tworzenie tych trzech kresek.

Kod HTML

Ten przedstawia się prosto, chociaż na pierwszy rzut oka może wydawać się lekko nadmiarowy:

<button class="hamburger" aria-label="Menu"> 
	<span class="hamburger__container" tabindex="-1"> 
    	<span class="hamburger__bars"></span> 
  	</span> 
</button>

Na zewnątrz mamy button i w nim spana w spanie. Ale po co w ogóle taki zabieg? Może od razu odeślę Cię do tego pytania na Stack Overflow . W skrócie chodzi o outline po ustawieniu focusu na nasz przycisk.

Nie chcemy widzieć go po kliknięciu w nasze menu, ale nie możemy go przecież zupełnie go wyzerować. Jeśli to zrobimy, to skąd chociażby osoba używająca klawiatury do nawigacji na stronie będzie wiedziała w jakim miejscu się znajduje? Ja też tego nie wiem. :/

Swoją drogą przy tym temacie zawsze uwielbiam wysyłać link do tej stronki , zapraszam tam, jeśli ten temat troszkę Cię zainteresował. Okej, o czym to ja mówiłem? Właśnie, CSS!

Kod CSS

W sumie, nas CSS, a w sumie to SCSS jest trooooszeczkę dłuższy:

.hamburger {
    margin: 0;
    padding: 0;
    border: 0;
    background-color: transparent;
    cursor: pointer;
    &:focus {
        & > .hamburger__container {
          	box-shadow: 0 0 2px 2px #51a7e8;
        }
    }
}

.hamburger__container {
    display: flex;
    align-items: center;
    position: relative;
    width: 35px;
    height: 30px;
}

.hamburger__bars {
    position: absolute;
    width: 35px;
    height: 2px;
    background-color: #000;
    transition: transform 220ms ease-in-out;
    &:before, &:after {
        display: block;
        position: absolute;
        width: 35px;
        height: 2px;
        background-color: #000;
        content: '';
    }
    &:before {
        top: -12px;
        transition: top 100ms 250ms ease-in, transform 220ms ease-in-out;
    }
    &:after {
        bottom: -12px;
        transition: bottom 100ms 250ms ease-in, 
          			transform 220ms ease-in-out;
    }
}

.hamburger--active {
    .hamburger__bars {
        transform: rotate(225deg);
        transition: transform 220ms 120ms ease-in-out;
        &:before {
            top: 0;
            transition: top 100ms ease-out;
        }
        &:after {
            bottom: 0;
            transform: rotate(-90deg);
            transition: bottom 100ms ease-out, 
            		  	transform 220ms 120ms ease-in-out;
        }
    }
}

.hamburger, .hamburger__container {
    &:focus {
      	outline: none;
  	}
}

Tak naprawdę najbardziej interesującym dla nas elementem jest .hamburger__bars, ponieważ to właśnie on odpowiada za wyświetlanie każdej z kresek. Jeśli chodzi o pozostałe reguły, zastosowane dla .hamburger oraz .hamburger__container, to one tak naprawdę sprowadzają się do wyzerowania domyślnych styli tych elementów, wypozycjonowania środkowej kreski oraz zadbania o efekt opisany podtytuł wyżej. Z kolei .hamburger__barsma tak naprawdę 2 stany. Domyślny oraz będący potomkiem klasy .hamburger—active, którą to dodajemy do naszego przycisku za pomocą kodu JS (oczywiście poruszymy jego kwestię troszkę później). W domyślnej wersji nasza kreska ma element beforeoraz after, które to zostały wypozycjonowane relatywnie do niej. Na wszystko oczywiście nałożyliśmy odpowiednie właściwości transition, aby wszystko ładnie się animowało:

.hamburger__bars {
    position: absolute;
    width: 35px;
    height: 2px;
    background-color: #000;
    transition: transform 220ms ease-in-out;
    &:before, &:after {
        display: block;
        position: absolute;
        width: 35px;
        height: 2px;
        background-color: #000;
        content: '';
    }
    &:before {
        top: -12px;
        transition: top 100ms 250ms ease-in, transform 220ms ease-in-out;
    }
    &:after {
        bottom: -12px;
        transition: bottom 100ms 250ms ease-in, 
          			transform 220ms ease-in-out;
    }
}

Gdy nasze hamburger menu stanie się już aktywne, to właściwości sprawiają, że afteri before zostają przesunięte do poziomu jednej kreski na środku, wszystko zostaje obrócone o 225 stopni, po czym sam afterzostaje jeszcze lekko przesunięty w przeciwną stronę, aby powstał ładny krzyżyk:

.hamburger--active {
    .hamburger__bars {
        transform: rotate(225deg);
        transition: transform 220ms 120ms ease-in-out;
        &:before {
            top: 0;
            transition: top 100ms ease-out;
        }
        &:after {
            bottom: 0;
            transform: rotate(-90deg);
            transition: bottom 100ms ease-out, 
            		  	transform 220ms 120ms ease-in-out;
        }
    }
}

I tak oto wygląda nasz cały element, mam nadzieję, że wszystko jest w miarę zrozumiałe. 🙂

I jak zawsze ostatni, ale równie istotny – kod JavaScript

Tu mamy już bardzo prosty skrypcik:

const menu = document.querySelector('.hamburger'); 

menu.addEventListener('click', () => { 
	menu.classList.toggle('hamburger--active'); 
});

Pobieramy element .hamburgeri później po prostu togglujemy klasę, która sprawia, że nasz element staje się aktywny (czyli w sumie tyle, że ładnie zamienia się w krzyżyk).

Kilka słów na koniec

I tak oto dotrwaliśmy do końca. Mam nadzieję, że mogłaś lub mogłeś wynieść wartość z tego artykułu i pokazane tu hamburger menu będzie mogło przydać Ci się w przyszłości. Oczywiście jeśli masz jakiekolwiek pytania lub sugestie, to proszę podziel się w komentarzu!

Komentarze

Może dodasz coś od siebie?