Responsive menu

W dzisiejszych czasach, gdy internet przeglądany jest na różnorakich urządzeniach tworzenie sztywnych nawigacji jest błędem. Jak wiemy, dobra nawigacja po naszej stronie to klucz do jej sukcesu, a przynajmniej jeden z głównych elementów wpływających na niego.

Stworzenie płynnego, dopasowującego się do wielkości ekranu menu wcale trudnym zadaniem nie jest, o czym przekonacie się już za chwilę.


Zanim przystąpimy do pracy, trochę teorii, którą jeżeli wiesz o co chodzi spokojnie możesz pominąć.

Jak wiecie, menu to jedna z najważniejszych rzeczy na naszej stronie. Jeżeli nie jest intuicyjne, wygodne w użytku to możecie zapomnieć o dużej ilości użytkowników (chyba że wasza strona nazywa się Facebook).
Popatrzmy na przykładowe menu.

mobile-menu

 

Nie wiem jak wy, ale ja nie dał bym rady trafić swoimi paluchami w tak małe elementy na mobilnych urządzeniach. Ok, powyżej pokazałem te urządzenia w mniejszych rozmiarach, ale i tak menu wydaje się być ciut za małe.
Jeżeli jesteśmy nieco mądrzejszymi webmasterami, zamiast sztywnego na szerokość menu, zrobimy takie, które dopasowuje się do rozdzielczości. Jednak i w tym przypadku będzie problem. Przy małych ekranach kolejne elementy nie zmieszczą się obok siebie i zostaną zawinięte jeden pod drugi. Tak czy siak wciąż będą dość małe, źle ułożone i nieprzyjemne do korzystania na telefonach.

Stąd właśnie najlepiej korzystać w takich przypadkach z techniki Responsive design, który w skrócie polega na tym, że layout zmienia swoje ułożenie w zależności od rozdzielczości ekranu. Jeżeli nie za bardzo wiesz o czym piszę, wtedy zapraszam cię do bardzo dobrego artykułu po polsku i innego po angielsku.

Zaczynamy pracę

Nasze menu będzie zwykłą listą UL:

<nav>        
    <ul>
        <li><a href="">Start</a></li>
        <li><a href="">Oferta</a></li>
        <li><a href="">Galeria</a></li>
        <li><a href="">Cennik</a></li>
        <li><a href="">O nas</a></li>
        <li><a href="">Kontakt</a></li>
    </ul>
</nav>

Dodajmy do niego trochę stylowania.

.clearfix:before, 
.clearfix:after { content: ''; display: table; }
.clearfix:after { clear: both; }
.clearfix { zoom: 1; }

body {
    margin:0;
}
nav {
    min-height:60px;
    background: rgb(51,51,51); /* Old browsers */
    background: -moz-linear-gradient(top,  rgba(51,51,51,1) 0%, rgba(17,17,17,1) 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(51,51,51,1)), color-stop(100%,rgba(17,17,17,1))); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top,  rgba(51,51,51,1) 0%,rgba(17,17,17,1) 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top,  rgba(51,51,51,1) 0%,rgba(17,17,17,1) 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(top,  rgba(51,51,51,1) 0%,rgba(17,17,17,1) 100%); /* IE10+ */
    background: linear-gradient(to bottom,  rgba(51,51,51,1) 0%,rgba(17,17,17,1) 100%); /* W3C */
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#333333', endColorstr='#111111',GradientType=0 ); /* IE6-9 */
}
nav ul {
    list-style:none; 
    padding:0; 
    margin:0;         
    font-size:0;
    display: block;        
}
nav ul li {
    display: inline-block;        
    max-width:100px;
    min-width:15%;
    text-align: center;
}    
nav ul li a {
    font:bold 14px/60px 'Open Sans', sans-serif;
    color:#eee;
    height:60px;
    display: block;
    text-decoration: none;        
    border-right:1px solid #444;
    border-left:1px solid #111;
}
nav ul li a:hover, nav ul li a:active, nav ul li a:focus {
    background: rgb(241,231,103); /* Old browsers */
    background: -moz-linear-gradient(top,  rgba(241,231,103,1) 0%, rgba(254,182,69,1) 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(241,231,103,1)), color-stop(100%,rgba(254,182,69,1))); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top,  rgba(241,231,103,1) 0%,rgba(254,182,69,1) 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top,  rgba(241,231,103,1) 0%,rgba(254,182,69,1) 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(top,  rgba(241,231,103,1) 0%,rgba(254,182,69,1) 100%); /* IE10+ */
    background: linear-gradient(to bottom,  rgba(241,231,103,1) 0%,rgba(254,182,69,1) 100%); /* W3C */
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f1e767', endColorstr='#feb645',GradientType=0 ); /* IE6-9 */
    color:#333;
    box-shadow:-4px 0 3px -3px rgba(0, 0, 0, 0.6) inset,4px 0 3px -3px rgba(0, 0, 0, 0.6) inset;
}

Kod wydłużają głównie css-owe gradienty, które jak zwykle tworzę z wykorzystaniem tego narzędzia.
Nie stosuję tutaj żadnych sztywnych miar szerokości. Przy wysokości nie ma tego problemu, ale żeby nasze menu ładnie się dopasowywało do szerokości, nie możemy korzystać z żadnych pixeli przy szerokościach (wyjątkiem jest max-width, które ogranicza nam zbytnie wydłużanie elementów przy szerokich ekranach). Dla listy ustawiłem rozmiar czcionki na 0, który od razu nadpisuję dla LI nową wartością. Dzięki temu między poszczególnymi elementami listy nie ma odstępów, które normalnie dla elementów typu display-block występują.

http://cssdeck.com/labs/ila3dylz/0

 

Jak masz szeroki monitor, to zobaczysz ładnie ułożone menu. Jeżeli masz mniejszą rozdzielczość, zobaczysz problemy, o których wspominałem powyżej. Przy małych rozdzielczościach poszczególne elementy menu mimo szerokości procentowej dochodzą do momentu, w którym nie mogą się dalej pomniejszać (przez wielkość czcionki) i zachodzą jedno pod drugie. Zajmiemy się tym przy okazji wersji dla urządzeń mobilnych.

Wersja mobilna

Mobilna wersja powinna mieć przede wszystkim duże, wyraźne linki. Dlatego elementy listy leżące obok siebie zamieniamy na duże leżące jeden pod drugim.
I teraz mała podpowiedź. Nowe stylowanie dla wersji mobilnej dopisujemy bezpośrednio pod tamtym stylowaniem. Dzięki temu będziemy widzieli nową mobilną wersję (którą potem podepniemy do odpowiedniej rozdzielczości) na bierząco.

...poprzednie stylowanie...

nav #input-toggle:checked ~ ul {
    max-height:500px;
}
nav ul li {
    border:0;
    width:100%;
    max-width: 100%;
    min-width:0;
    border-bottom:1px solid #333;

}
nav ul li a {
    display: block;
    text-align: center;
}

http://cssdeck.com/labs/mletn4fz/0

 

Wszystko pięknie i ładnie, ale w obecnej formie po wejściu na naszą stronę na telefonie zamiast treści zobaczymy tylko nasze wysokie menu, które przykryje cały ekran.
Idąc więc za popularnym ostatnio trendem dodamy znaną i lubianą ikonkę, która służy do rozwijania wersji mobilnej menu.

ikonka-menu

Pisać na jej temat nie będę, bo w przytoczonym artykule napisano wszystko co napisać było można :) Zamiast przedłużać, bierzemy się do dalszej roboty.
Większość tutoriali stosuje tutaj JS, ale tak naprawdę wcale nie musimy zapuszczać do takiego rozwijania skryptów.
Wystarczy wykorzystać technikę zaprezentowaną w tym tutorialu, która polega na stylowaniu elementu który leży bezpośrednio za inputem typu checkbox (któremu możemy pobierać stany za pomocą pseudoselektora :checked). Ogólnie ta technika ma postać:

.input-checkbox + .menu {......}
.input-checkbox:checked + .menu {......}

Samego checkboxa zbytnio stylować nie możemy, dlatego go ukrywamy, a zmieniamy wygląd dla labela, który odnosi się do tego ukrytego checkboxa :)
I to właśnie ten label będzie naszym guzikiem pokazującym menu.

<nav>        
    <label for="input-toggle">
        <span></span>
        <span></span>
        <span></span>
    </label>

    <input type="checkbox" id="input-toggle">    
    <ul>
        <li><a href="">Start</a></li>
        <li><a href="">Oferta</a></li>
        <li><a href="">Galeria</a></li>
        <li><a href="">Cennik</a></li>
        <li><a href="">O nas</a></li>
        <li><a href="">Kontakt</a></li>
    </ul>
</nav>

Doszedł nam omawiany checkbox, oraz labelka, która ma w sobie 3 spany (trzy białe kreseczki w naszym przycisku).
Dodać stylowanie do labelki i checkboxa:

#input-toggle {
    opacity:0;
    position: absolute;
    top:0;
    left:0;
}

.navigation-toggle { 
    display:block;
    width:44px; 
    height:33px; 
    margin:5px; 
    text-align:center; 
    border-radius:4px; 
    border:1px solid #404040; 
    background-image: linear-gradient(to bottom, #000, #111); 
    background-repeat: repeat-x; 
    color:#FFFFFF; 
    text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 
    padding-top:10px; 
    position:absolute; 
    top:2px; right:2px; 
    cursor:pointer; 
}
.navigation-toggle span { 
    background-color: #F5F5F5; 
    border-radius: 1px 1px 1px 1px; 
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); 
    display:block; 
    height:2px; 
    width:18px; 
    margin:4px auto; 
}
nav ul {
    margin-top:55px;
    overflow: hidden;                
    max-height:0;
    transition:max-height 0.35s ease 0s;
    -webkit-transition:max-height 0.35s ease 0s;
    -moz-transition:max-height 0.35s ease 0s;
}
nav #input-toggle:checked + ul {
    max-height:500px;
}

Chcąc uzyskać animację rozwijania menu nie możemy zwyczajnie zmieniać mu wartości display. Trzeba zmieniać jego wysokość. Ale zmiana wysokości z height:0 (menu ukryte) na height:auto nie współgra z transition, czyli nie uzyskujemy animacji. Dlatego właśnie korzystamy z min-height, który sprawdza się wyśmienicie.

http://cssdeck.com/labs/p4xmflii/0

 

Tak naprawdę całą pracę mamy już skończoną. Pozostaje naszą wersję mobilną objąć odpowiednim media queries

@media screen and (max-width:500px) {
      ....tutaj leci nasz kod dla mobilnych wersji...
}

I to wszystko. Gotową wersję z lekko uporządkowanym kodem css możesz zobaczyć pod poniższym linkiem:

Finalne menuNie zapomnij podłubać przy wielkości okna przeglądarki by zobaczyć jak ładnie zmienia się nasze dzieło.

Niestety powyższa metoda taka cudowna nie jest. Na mobilnych przeglądarkach istnieje błąd, który powoduje, że trik z checkboxem nie działa. Jest na to jednak bardzo proste lekarstwo.
Więcej na ten temat przeczytasz tutaj: http://timpietrusky.com/advanced-checkbox-hack

Komentarze

  • atp

    Rozumiem że kodowanie powinno być „responsible” ale to o czym piszesz to responsive webdesign :)

    • kartofelek007

      Responsible web design, responsible design, responsible layouts itp. Nazwy są różne. Samego kodowania pod taką nazwą nie ma. Jest za to odpowiednie podejście, idea. A powyższy wpis to tylko maluteńki wycinek tej idei.

      • atp

        Chodzi o pierwsze słowo a nie o drugie ;)

        responsible = odpowiedzialny
        responsive = reagujący

        …albo Ci automatyczna korekta coś poprawia albo nie wiesz o czym piszesz :P

      • kartofelek007

        Nawet tego nie zauważyłem :) Już poprawione. Chociaż w sumie obie wersje tutaj pasują :)

  • piotrek

    Jak najbardziej jest za tego typu artykułami. W następnych odcinkach mógłbyś napisać coś o praktycznych podstawach, np. jak manipulować rozmiarami czcionek, marginesami, paddingami itp. pod względem różnych urządzeń.
    Gdzie stosować piksele, gdzie em-y lub procenty :)
    Responsive desing to przyszłość i teraźniejszość, kto zostanie przy sztywnym 960 ten umrze :)

    • kartofelek007

      Nie wyginie :) 960 to taki sam grid jak reszta. A zmuszenie go do płynności też nie jest jakimś mega wyzwaniem.
      Same płynne layouty wcale nie są czymś nowym. W końcu 99% forów itp od zawsze było płynnymi. Ba. Nawet tabelkowe layouty były bardziej płynne niż te na divach (pamiętacie width=”100%”?)

      Chodzi po prostu o lepszą obsługę urządzeń mobilnych. Zwykłe laje tam się nie sprawdzają i kropka.
      Laje wcale nie muszą być totalnie płynne. Sporo osób robi stałe layouty i używa tak zwanych „breakpointów” czyli ustala w którym momencie (rozdzielczość) layout się zmienia. To też bardzo dobre rozwiązanie. Dobre, bo mamy o wiele większą kontrolę nad tym co widzimy i robimy. No ale to już temat na kolejne artykuły :)

  • Konrad

    Media Queries jest obecnie trochę bez sensu ponieważ nie na każdym telefonie działa. Twoja strona tez używa Media Queries. Co prawda gdy zmniejszę okno przeglądarki na komputerze to się dopasuje , lecz na moim telefonie(Xperia U) wyświetla się się normalna „komputerowa” strona. Lepszym sposobem jest napisanie wersji mobilnej w javascript, czyli co 1 milisekundę sprawdzać rozdzielczość ekranu i w odpowiednim momencie podmienić styl na odpowiadający rozdzielczości.

    • kartofelek007

      Nie przejmuj się moją stroną. ona jest w fazie tworzenia, non stop ją zmieniam i nie jest jeszcze skończona. Moim zdaniem Media Queries już teraz jest standardem. Oczywiście tak samo jak z CSS3 trzeba go używać z głową. Twoje rozwiązanie np nie zadziała na telefonach na których nie działa JS. To tak samo jak PNG nie zadziałają na IE6, jak Flash nie zadziała na niektórych telefonach itp. ALE! Ale na całej reszcie będzie działać jak należy. Wszystkich nie zadowolisz. No chyba że kosztem całej reszty (kilka takich robiących pętlę skryptów i zatniesz nawet dobrą maszynkę). Nie neguję twojego rozwiązania. To tylko inna metoda na to samo. Osobiście wolę standardy, ale wiadomo – w praktyce one nie zawsze się sprawdzają. Pisząc podobne artykuły jak powyższy mam nadzieję, że moi czytelnicy mają trochę w głowie i wiedzą, że część wiadomości może być niedopowiedziana, a niektóre sprawy i problemy samemu trzeba zgłębić. Ot zaufanie do czytelników :)

    • atp

      Nie ma deklaracji meta viewport w sekcji head tej strony – dlatego na Twoim tel, jak i na większości urządzeń mobilnych, wyświetli się „duża” wersja … Wystarczy dodać odpowiednią deklarację i będzie śmigać :)

      • kartofelek007

        Jak to pięknie czytać komentarze. Właśnie zauważyłem, że tworząc layout dla wordpressa zapomniałem przez to całe zamieszanie dodać odpowiednich nagłówków do headera ;} No ale jak pisałem, jeszcze trochę przed tą stroną. Nieco dużo :) Podziękować.

    • atp

      …a odnośnie sprawdzania przez js co 1 milisekundę rozdzielczości ekranu czy tam szerokości przeglądarki to raczej nietrafiony pomysł ponieważ ilu ludzi podczas przeglądania stron zmniejsza/zwiększa rozdzielczość/rozmiar okna przeglądarki!? Myślę że tak naprawdę to nikt :) Osobiście czasami używam czegoś w stylu:

      if ($(window).width() < 1024)

      …żeby np. na „dużej” wersji strony wyświetlał się lightbox, a na mniejszych wyświetlaczach coś na full page ;)

      • Nie zgodzę się z Tobą , atp.
        Często korzystam ze smartfonów i po obróceniu urządzenia do orientacji poziomej/pionowej przeglądarka wyświetla stronę w nowej szerokości. Na przykład zmienia szerokość z 240 na 320. Co prawda procenty i @m-q powinny działać ale są wyjątki, zatem odpowiednia wtyczka (metoda jquery) jest bardzo ciekawym pomysłem.

        Swoją drogą popieram stwierdzenie, że artykuły na tym blogu są pisane do osób z przynajmniej podstawową wiedzą.

        Dobra robota!
        PS. Bootstrap działa na SONY XPERIA (przynajmniej u mnie)

  • Pingback: Transition CSS3 i slider - doman.art.pl()