liquiddesign

Wzorzec 10

Zakładki bez windy

Każda zakładka niesie inną ilość treści, więc naiwny panel zmienia wysokość przy każdym przełączeniu i wszystko pod nim faluje. Wystarczy położyć wszystkie panele w jednej komórce siatki: nieaktywne są niewidzialne, ale wciąż liczą się do wysokości.

Te same zakładki, dwa panele

Jeden pasek steruje oboma panelami. Lewy renderuje tylko aktywną treść i faluje, prawy trzyma wysokość najdłuższej zakładki.

✕ Wysokość za aktywną zakładką

Rebranding studia Atlas: nowa identyfikacja, strona i system szablonów dla zespołu marketingu.

Obserwuj tę linię przy przełączaniu

✓ Rezerwa najwyższego panelu

Rebranding studia Atlas: nowa identyfikacja, strona i system szablonów dla zespołu marketingu.

Obserwuj tę linię przy przełączaniu

Reguły

  • Wszystkie panele mieszkają w jednej komórce grid, aktywny jest widoczny, reszta niewidzialna.
  • Wysokość sekcji to maksimum ze wszystkich paneli, policzone przez przeglądarkę, nie przez skrypt.
  • Nieaktywne panele mają visibility hidden oraz inert, więc są poza fokusem i czytnikami.
  • Przełączenie zakładki nie przesuwa niczego poza zawartością panelu.

Wzorzec w kodzie

Panele w jednej komórce, invisible i inert zamiast unmountu
<div className="grid">
  {tabs.map((tab) => (
    <div
      key={tab.id}
      role="tabpanel"
      inert={active !== tab.id}
      className={
        active === tab.id
          ? "col-start-1 row-start-1"
          : "col-start-1 row-start-1 invisible"
      }
    >
      {tab.content}
    </div>
  ))}
</div>
Zakładka to tab z aria-selected
<button
  role="tab"
  aria-selected={active === tab.id}
  aria-controls={"panel-" + tab.id}
  onClick={() => setActive(tab.id)}
>
  {tab.name}
</button>