< Poprzedni Budowanie serwisu mucka.pro Następny >
11 Feb 2025

Menu główne

Graficzny interfejs użytkownika działa najlepiej jak jest spójny. Elementy nawigacyjne powinny wynikać ze struktury strony. Najważniejszym elementem nawigacyjnym strony jest zwykle menu główne. Pozwala ono użytkownikowi wstępnie zapoznać się ze strukturą strony. Często też pozwala wydostać się z labiryntu odnośników.

Pomysł

Na tym etapie chciałbym minimalistyczne menu z kilkoma odnośnikami. Umieszczę tam kilka najważniejszych działów. Domyślnie menu powinno mieć horyzontalną strukturę. Pierwszym elementem menu powinien być odnośnik do strony domowej.

Rysunek 1. Pomysł horyzontalnego menu dla dużych ekranów

Na mniejszych ekranach menu powinno być rozwijane i wertykalne. Menu powinno być rozwijane na całą szerokość ekranu. Rozważam zaopatrzenie elementów menu w graficzne ikony.

Rysunek 2. Pomysł wertykalnego menu dla małych ekranów

Implementacja

Na początku implementacji rozrysowałem wizję finalnego html. Szkic przedstawiony na listingu 1. Struktura jest częściowo wymuszona przez możliwości css. Zdarzenie :hover czy :active może wpływać na styl innych elementów. Możemy do tego wykorzystać operator ~. Musimy pamiętać o jego ograniczeniach. Elementy na które będziemy chcieli wpływać muszą znajdować się pod elementem wskazywanym, wewnątrz tego samego tagu.


<div class="mainmenu">
  <a class="menu"/>
  <div class="mainmenu big">
    <span class="hide top">Menu główne</span>
    <a href="/pl/root.xhtml" class="home">
      <span class="hide">Strona główna</span>
    </a>
    <a href="/pl/news.xhtml" class="news">Aktualności</a>
    <a href="/pl/articles.xhtml" class="articles">Artykuły</a>
    <a href="/pl/notes.xhtml" class="notes">Notatki</a>
    <a href="/pl/contact.xhtml" class="contact">Kontakt</a>
  </div>
</div>
  
Listing 1. Propozycja sekcji menu głównego

Szablon przedstawiony na listingu 2 wkomponowałem w istniejące podstrony: main.xhtml, list.xhtml oraz content.xhtml.


<div class="mainmenu">
  <a class="menu"/>
  <div class="mainmenu big">
    <!-- MAINMENU -->
  </div>
</div>
  
Listing 2. Szablon menu głównego

Arkusz stylów

Na początek postanowiłem uwspólnić kolorystykę w arkuszu. Dodałem do selektora :root kilka elementów przestawionych na listingu 3.


:root {
  --default-width: 95%;
  --menu-width: 100%;
  --menu-max-height: 80vh;

  --light-background: #f0f0f1;
  --middle-background: #c3c4c7;
  --dark-background: #8c8f94;

  --bold-font-color: #121213;

  --dark-highlight: #6c944b;
  --light-highlight: #b9d7a2;
}
  
Listing 3. Nowy selektor root w arkuszu stylów

Ustawiam podstawowe selektory, przedstawione na listingu 4. Wysokość menu ustawiam na 40 pikseli. Margines gówny, odstęp od loga, ustawiam na 20 pikseli. Kolor menu ustawiam na ciemny. Ukrywam elementy przeznaczone do ukrycia za pomocą parametru display: none. Ustawiam parametr display na table-cell dla tagu <a>. Staram się uniknąć w ten sposób dużej ilości nadmiarowych tagów <div>.


.mainmenu {
  margin-top: 20px;
  height: 40px;
  background-color: var(--dark-background);
}

.mainmenu span.hide {
  display: none;
}

.mainmenu a {
  display: table-cell;
}
  
Listing 4. Podstawowe selektory mainmenu

Podstawowe ustawienia pojedynczego elementu menu przedstawione na listingu 5. Bloczek menu ma mieć wymiary 40x100 pikseli. Tekst ma być pogrubiony oraz znajdować się centralnie.


.mainmenu span.top,
.mainmenu a {
  height: 40px;
  width: 100px;
  line-height: 40px;
  text-align: center;
  text-decoration: none;
  color: var(--bold-font-color);
  font-weight: 700;
  cursor: pointer;
}
  
Listing 5. Bazowe parametry pojedynczego elementu menu

Detale niektórych elementów menu przedstawione na listingu 6. Aktualnie wybrany element wyróżniam jasnym kolorem. Odnośnik powrotu na stronę domową wyróżniam grafiką domu. Przycisk wyzwalające menu rozwijane wyróżniam grafiką menu. Ten przycisk jest domyślnie niewidoczny.

Na małych ekranach cały <div> klasy mainmenu big zmienia organizację z poziomej na pionową. Zmiany przedstawione na listingu 7. Ustawiam 300 milisekundową animację przejścia. Ustawiam pozycje w absolutnym układzie współrzędnych na (0, 0). Menu powinno przesłaniać resztę inne elementy strony, do tego wykorzystuję parametr z-index. Szerokość menu głównego ustawiam na 0. Parametrem szerokości będę manipulował aby odsłaniać i chować menu

Na listingu 8 przedstawiłem parametr odpowiedzialny za rozwijanie menu i utrzymanie go w stanie rozwiniętym. Dodatkowo zdefiniowałem kolory tła. W czasie dopracowywania menu uznałem, że tło horyzontalnego i wertykalnego menu będzie się różnić. Horyzontalne menu lepiej wygląda ciemniejsze. Wertykalne menu jest zdecydowanie bardziej czytelne jaśniejsze.


@media only screen and (max-width: 800px) {
  .mainmenu a.menu:hover ~ .mainmenu.big,
  .mainmenu.big:hover {
    width: var(--menu-width);
  }

  .mainmenu a.element {
    background-color: var(--middle-background);
  }

  .mainmenu a.element:hover {
    background-color: var(--light-background);
  }
}
  
Listing 8. Selektor opisujący efekt rozwijania menu

Część elementów menu, takich jak belka tytułowa jest ukrytych w wersji wertykalnej. W wersji horyzontalnej odkrywam je za pomocą parametru display. Przedstawione jest to na listingu 9.

W pierwszej wersji elementy wertykalnego menu były samym tekstem. Testowałem różne wyrównania tekstu i warianty kolorystyczne. Żaden wariant nie był w stanie mnie przekonać do zamknięcia tego tematu. Po dłuższym zastanowieniu się dodałem elementom prostą grafikę. Menu główne stało się bardziej spójne z językowym. Zostawiam ten element na razie. Uzupełnienie elementów menu o kropki przedstawione na listingu 10. Dodatkowo podmieniłem ikonę "domku" na inną, bardziej pasującą do menu wertykalnego, zostawiając menu horyzontalne jak jest.

Na koniec ostatni ważny element przedstawiony na listingu 11. Nięzbędnym elementem do przejścia z horyzontalnego menu na wertykalne jest zmiana parametru display z table-cell na block.

Generator

Nowa funkcja generatora przedstawiona na listingu 12 jest krótka i prosta. Korzystając z kilku słowników: main_menu, main_page, content_type_filename i content_type_name_plural wypełnia kilka tagów <a> i <span>. Można powiedzieć, że jedyna funkcja tego kodu to translacja menu na odpowiedni język.


def render_main_menu(language):
    '''Render main menu'''
    result  = f'<span class="hide top">{main_menu[language]}</span>'
    result += f'<a href="/{language}/root.xhtml" class="element home">\n'
    result += f'<span class="hide">{main_page[language]}</span>\n'
    result += '</a>\n'
    for element in ['news', 'article', 'note', 'contact']:
        filename = content_type_filename[element]
        plural = content_type_name_plural[element][language]
        result += f'<a href="/{language}/{filename}" class="element {element}">{plural}</a>\n'
    return result

  
Listing 12. Sekcja generatora odpowiedzialna za menu główne

Całość implementacji można znaleźć w następujących commitach:

Efekt

Efekt finalny dla większych rozdzielczości przedstawiony na rysunku 3 Efekt finalny dla mniejszych rozdzielczości przedstawiony na wideo 1. Dopasowałem do siebie styl meny głównego i menu językowego. Dodatkowo zmieniłem lekko styl nagłówków tabel.

Rysunek 3. Strona razem z menu głównym

Rysunek 3 przedstawia wczesny etap. Kolory nie są jeszcze finalne. Menu językowe jest jeszcze niezmienione. Tabele są jeszcze renderowane po staremu Wideo 1 przedstawia finalny efekt.

Wideo 1. Strona razem z menu głównym

Podsumowanie

To był męczący i czasochłonny element. Wstyd się przyznać, spaliłem kilka godzin na pierwszą rewizję. Byłem w miarę zadowolony, ale nie do końca. Następnie spaliłem kolejnych kilka godzin za poprawki. Pisząc ten artykuł dodawałem kolejne poprawki. Jak zwykle, najwięcej czasu zabierają mi zadania związane z graficznym interfejsem użytkownika. Wykorzystałem sporo CSS'a napisanego wcześniej na potrzeby menu językowego. Oszczędziło trochę czasu, ale nie uratowało od dużej ilości małych poprawek. Mści się próba implementacji bez dokładnego projektu graficznego.

release date: 11 Feb 2025
language: pl
stage: release
type: article
tags: python html css
< Poprzedni Budowanie serwisu mucka.pro Następny >