Ćwiczenia z programowania: tworzenie komponentu Sidenav

Z tego ćwiczenia w Codelabs dowiesz się, jak utworzyć elastyczny komponent układu nawigacji bocznej wysuwanej na stronie internetowej. Komponent będziemy tworzyć stopniowo, zaczynając od HTML, potem CSS i JavaScript.

Więcej informacji o funkcjach platformy internetowej CSS wybranych do utworzenia tego komponentu znajdziesz w moim artykule na blogu Building a Sidenav component.

Konfiguracja

  1. Kliknij Remiksuj, aby edytować, aby umożliwić edycję projektu.
  2. Otwórz pokój app/index.html.

HTML

Najpierw poznaj podstawy konfiguracji HTML, aby mieć treść i pola, z którymi możesz pracować.

Wklej ten kod HTML do tagu <body>.

<aside></aside>
<main></main>

Element <aside> zawiera menu nawigacyjne jako element uzupełniający element <main>, który zawiera główną treść strony.

Następnie wypełnimy te elementy semantyczne pozostałą zawartością strony.

Dodaj element nawigacyjny, linki nawigacyjne i link zamykający w elemencie <aside>.

<aside>
  <nav>
    <h4>My</h4>
    <a href="#">Dashboard</a>
    <a href="#">Profile</a>
    <a href="#">Preferences</a>
    <a href="#">Archive</a>

    <h4>Settings</h4>
    <a href="#">Accessibility</a>
    <a href="#">Theme</a>
    <a href="#">Admin</a>
  </nav>

  <a href="#"></a>
</aside>

Linki świetnie pasują do elementów <nav>, a elementy <nav> świetnie pasują do pasków bocznych <aside>. Mimo to możemy jeszcze wiele zrobić, aby ulepszyć tę funkcję.

W elemencie treści głównej dodaj nagłówek i artykuł, aby semantycznie przechowywać zawartość układu.

<main>
  <header>
    <a href="#sidenav-open" class="hamburger">
      <svg viewBox="0 0 50 40">
        <line x1="0" x2="100%" y1="10%" y2="10%" />
        <line x1="0" x2="100%" y1="50%" y2="50%" />
        <line x1="0" x2="100%" y1="90%" y2="90%" />
      </svg>
    </a>
    <h1>Site Title</h1>
  </header>

  <article>
    {put some placeholder content here}
  </article>
</main>

W nagłówku znajduje się link do otwarcia menu. W sekcji bocznej znajduje się przycisk zamykania. Wkrótce będziemy wyświetlać i ukrywać elementy w zależności od rozmiaru obszaru wyświetlania.

W elemencie <article> wkleiliśmy przykładowe zdanie. Zastąp `` własnymi treściami lub wklej tekst lorem podany poniżej:

<h2>Totam Header</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cum consectetur, necessitatibus velit officia ut impedit veritatis temporibus soluta? Totam odit cupiditate facilis nisi sunt hic necessitatibus voluptatem nihil doloribus! Enim.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

<h3>Subhead Totam Odit</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

<h3>Subhead</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

To właśnie ta treść i jej długość sprawiają, że strona jest przewijalna, gdy przekracza wysokość widocznego obszaru.

Do tej pory dodaliśmy element aside z elementem nav, linkami i sposobem zamykania panelu bocznego. Dodano też nagłówek, sposób otwierania panelu bocznego i artykuł do elementu głównego. Jest to czysty, semantyczny i dość ponadczasowy kod, ale możemy go jeszcze bardziej uprościć i ułatwić zrozumienie. Link otwierający w panelu bocznym mógłby być wyraźniej oznaczony.

Dodaj atrybuty titlearia-label do elementu otwierającego link w nagłówku:

<a href="#sidenav-open" class="hamburger">
<a href="#sidenav-open" title="Open Menu" aria-label="Open Menu" class="hamburger">

Ikona otwartego pliku SVG mogłaby być też wyraźniej oznaczona. Dodaj te atrybuty do elementu SVG wewnątrz elementu otwartego linku:

<svg viewBox="0 0 50 40">
<svg viewBox="0 0 50 40" role="presentation" focusable="false" aria-label="trigram for heaven symbol">

Link zamykający w panelu bocznym mógłby być wyraźniej oznaczony. Dodaj atrybuty titlearia-label do elementu linku zamykającego panel boczny:

<a href="#"></a>
<a href="#" title="Close Menu" aria-label="Close Menu"></a>

CSS

Czas rozmieścić elementy. Główna treść i pasek boczny są bezpośrednimi elementami podrzędnymi tagu <body>, więc to dobry punkt wyjścia.

Dodaj ten kod CSS do css/sidenav.css, aby element <body> rozmieszczał elementy podrzędne.

body {
  display: grid;
  grid: [stack] 1fr / min-content [stack] 1fr;

  @media (max-width: 540px) {
    & > :matches(aside, main) {
      grid-area: stack;
    }
  }
}

Ten układ zasadniczo oznacza: utwórz nazwany wiersz stack ze wszystkimi elementami w nim i 2 kolumnami w tym wierszu, z których druga również ma nazwę stack. Szerokość pierwszej kolumny powinna być dostosowana do minimalnych potrzeb związanych z zawartością, a druga kolumna może zajmować pozostałą część. Następnie, jeśli w ograniczonym widocznym obszarze o szerokości 540px lub mniejszej, umieść elementy panelu bocznego i głównej treści w tym samym wierszu i kolumnie, co spowoduje, że będą one ułożone jeden na drugim w siatce 1x1.

Dzięki tej funkcji elastycznego układania możemy teraz wykorzystać stan paska adresu URL do przełączania widoczności i stylu przejścia panelu bocznego.

Zaktualizuj element <aside>app/index.html:

<aside>
<aside id="sidenav-open">

Umożliwia to porównywarce cenowe dopasowanie elementu i skrótu adresu URL. Jest to ważne w przypadku korzystania z :target. Teraz identyfikator elementu może być zgodny z haszem adresu URL, który ustawimy za pomocą tagów <a>.

Dodatkowo, aby ułatwić kierowanie na JavaScript, dodaj identyfikatory kluczowych elementów, które kontrolują panel boczny. Najpierw dodaj identyfikator do linku otwierającego panel boczny:

<a href="#sidenav-open" class="hamburger" title="Open Menu" aria-label="Open Menu">
<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">

Następnie dodaj identyfikator do linku zamykającego panel boczny:

<a href="#" title="Close Menu" aria-label="Close Menu"></a>
<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

To kończy makro <body> elastycznego układu w formie stosu, a także wiąże nas z paskiem adresu URL. Kontynuujmy!

<aside> ma też przejrzysty układ. Zawiera 2 elementy podrzędne: <nav>, który jest wysuwanym komponentem przypominającym papier, oraz zamykający element linku <a>, który ustawia adres URL na #. Link jest niewidoczny po prawej stronie wysuwanego menu papierowego. Umożliwia on „kliknięcie” komponentu wizualnego w celu jego zamknięcia.

Dodaj do pliku css/sidenav.css ten kod CSS:

#sidenav-open {
  display: grid;
  grid-template-columns: [nav] 2fr [escape] 1fr;
}

Uważam, że proporcje i nazwy to świetny pomysł, który pozwala w pełni wykorzystać możliwości siatki i zapewnia projektantowi dużą kontrolę.

Następnie muszę warunkowo nałożyć główną treść i zachować pozycję podczas przewijania dokumentu. To świetna praca dla position: sticky i overscroll-behavior.

Dodaj te style do paska bocznego:

#sidenav-open {
  display: grid;
  grid-template-columns: [nav] 2fr [escape] 1fr;

  @media (max-width: 540px) {
    position: sticky;
    top: 0;
    max-height: 100vh;
    overflow: hidden auto;
    overscroll-behavior: contain;

    visibility: hidden; /* not keyboard accessible when closed */
  }
}

Te style zapewniają, że panel boczny ma wysokość widocznego obszaru, przewija się w pionie i zawiera przewijanie. Co bardzo ważne, ukrywa element. Domyślnie, gdy obszar widoku ma rozmiar 540px lub mniejszy, ukryj ten panel boczny. Chyba że…

Dodaj pseudo-selektor :target do elementu #sidenav-open:

#sidenav-open {

  @media (max-width: 540px) {

    &:target {
      visibility: visible;
    }
  }
}

Jeśli identyfikator tego elementu i paska adresu URL są takie same, ustaw wartość visibility na visible. Otwórz menu boczne po przewinięciu strony lub spróbuj przewinąć stronę, gdy menu boczne jest otwarte. Co myślisz?

Dodaj ten kod CSS na końcu pliku app/sidenav.css:

#sidenav-button,
#sidenav-close {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  user-select: none;
  touch-action: manipulation;

  @media (min-width: 540px) {
    display: none;
  }
}

Te style są przeznaczone dla przycisków otwierania i zamykania, określają ich style kliknięcia i dotyku, a także ukrywają je, gdy obszar wyświetlania ma rozmiar 540px lub większy.

Dodajmy trochę stylu, stosując przekształcenia CSS z zachowaniem dostępności. Dodaj do pliku css/sidenav.css ten kod CSS:

#sidenav-open {
  --easeOutExpo: cubic-bezier(0.16, 1, 0.3, 1);
  --duration: .6s;

  ...

  @media (max-width: 540px) {
    ...

    transform: translateX(-110vw);
    will-change: transform;
    transition:
      transform var(--duration) var(--easeOutExpo),
      visibility 0s linear var(--duration);

    &:target {
      visibility: visible;
      transform: translateX(0);
      transition: transform var(--duration) var(--easeOutExpo);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    --duration: 1ms;
  }
}
Prezentacja interakcji z zastosowaniem czasu trwania i bez niego na podstawie zapytania o media `prefers-reduced-motion`.

Dodaj trochę JavaScriptu

Klawisz Escape powinien zamknąć menu. Dodaj ten kod JavaScript do pliku js/index.js:

const sidenav = document.querySelector('#sidenav-open');

sidenav.addEventListener('keyup', e => {
  if (e.code === 'Escape') {
    document.location.hash = '';
  }
});

Nasłuchuje kluczowego zdarzenia w elemencie panelu bocznego. Jeśli jest to Escape, ustawia hash adresu URL na pusty, co powoduje wyjście z przejścia bocznego.

Kolejnym elementem UX JS jest zarządzanie fokusem. Chcę, aby otwieranie i zamykanie było łatwe, więc czekam, aż pasek boczny zakończy przejście, a potem sprawdzam go z haszem adresu URL, aby określić, czy jest otwarty, czy zamknięty. Następnie używam JavaScriptu, aby ustawić fokus na przycisku uzupełniającym ten, który został właśnie naciśnięty.

Dodaj ten kod JavaScript do js/index.js:

const closenav = document.querySelector('#sidenav-close');
const opennav = document.querySelector('#sidenav-button');

sidenav.addEventListener('transitionend', e => {
  if (e.propertyName !== 'transform') {
    return;
  }

  const isOpen = document.location.hash === '#sidenav-open';

  isOpen
    ? closenav.focus()
    : opennav.focus();
});

Wypróbuj

  • Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację, a następnie Pełny ekran pełny ekran.

Podsumowanie

To wszystko, czego potrzebowałem w przypadku tego komponentu. Możesz go rozbudowywać, sterować nim za pomocą stanu JavaScript zamiast adresu URL i ogólnie dostosowywać go do swoich potrzeb. Zawsze można dodać coś nowego lub omówić kolejne przypadki użycia.

Otwórz css/brandnav.css, aby sprawdzić style niezwiązane z układem, które zostały zastosowane do tego komponentu. Nie uważałem, że jest to ważne w przypadku funkcji, na których się skupiałem, i miałem nadzieję, że oddzielenie stylów od układu zachęci do kopiowania i wklejania. Możesz tam znaleźć więcej informacji.

Jak tworzyć wysuwane komponenty paska bocznego, które dostosowują się do rozmiaru ekranu? Czy zdarza się, że masz więcej niż 1, np. po obu stronach? Chętnie zaprezentuję Twoje rozwiązanie w filmie na YouTube. Napisz do mnie na Twitterze lub dodaj komentarz na YouTube z kodem. Pomoże to wszystkim.