SST - Einheitlicher Standard für Registerkarten

SST - Einheitlicher Standard für Registerkarten
Standards

62

6 min.

Definitionen

Der SST-Standard legt Anforderungen an die Semantik, Barrierefreiheit und Funktionslogik von Registerkarten fest.

Struktur und Verhalten

Container und Scrollen

  • Tabs bleiben in einer einzigen Zeile. Gemäß der SST-A-Konvention werden sie auf schmalen Bildschirmen weder in eine zweite Zeile umgebrochen noch durch ein Dropdown ersetzt.
  • Die Tab-Leiste erhält einen eigenen Container mit overflow-x: auto. Nur die Leiste scrollt horizontal, nicht die gesamte Seite; der Inhalt des geöffneten Panels muss sich an die Viewportbreite anpassen.
  • Tabs werden nicht auf eine zweite Zeile umgebrochen. Sie behalten ihre Breite; bei Überlauf ermöglicht der Container das horizontale Scrollen.
  • Soweit möglich, bleibt am Containerrand ein Teil des nächsten Tabs sichtbar — ungefähr 10–20px. Dies signalisiert, dass die Liste weitergeht, und kann dekorative Pfeilindikatoren überflüssig machen. Die Beschriftung oder der Fokusindikator des aktiven Tabs darf nicht abgeschnitten werden; dieser visuelle Hinweis ersetzt keine Tastaturnavigation.
  • Auf Mobilgeräten kann die System-Scrollleiste ausgeblendet werden, wenn die Scrollmöglichkeit durch einen teilweise sichtbaren nächsten Tab oder einen anderen Hinweis erkennbar bleibt. Das Ausblenden darf die Tastaturbedienung des Scrollbereichs nicht verhindern.
  • -webkit-overflow-scrolling: touch ist keine grundlegende Voraussetzung für flüssiges Scrollen. Aktuelle iOS- und iPadOS-Versionen beschleunigen das Scrollen in Overflow-Bereichen auch ohne diese Eigenschaft; auf dem iPhone kann sie außerdem einen Stacking Context erzeugen. Sie wird nur für ausdrücklich unterstützte ältere Versionen und nach Tests auf Geräten ergänzt.

Aktiver Tab und Zentrierung

  • Der aktive Tab erhält einen deutlichen visuellen Zustand, zum Beispiel eine Akzentlinie oder einen geänderten Hintergrund. Der Unterschied darf nicht allein durch Farbe vermittelt werden.

  • Bei der Auswahl eines Tabs, einer Bewegung des Tastaturfokus oder beim Öffnen eines direkten Links wird die Leiste so gescrollt, dass der ausgewählte Tab sichtbar und möglichst nahe an der Mitte liegt.

  • Die Zentrierung ist durch den verfügbaren Scrollbereich begrenzt: Der erste und letzte Tab am Rand des Containers können nicht immer exakt mittig positioniert werden.

  • Für eine Links-nach-rechts-Ausrichtung lässt sich der Zielwert relativ zum Anfang des scrollbaren Inhalts berechnen:

    targetScrollLeft = clamp(tabStart + tabWidth / 2 - viewportWidth / 2, 0, scrollWidth - viewportWidth)

    Dabei ist tabStart die Position des Tabs relativ zum Anfang der Scroll-Leiste. Bei RTL-Layouts sind Schreibrichtung und Unterschiede beim horizontalen Scrollverhalten zu berücksichtigen; nach Möglichkeit wird logisches Scrollen des Elements verwendet.

Identifikation und URL

Beziehungen zwischen Tabs und Panels

  • Der Container erhält role="tablist" und einen zugänglichen Namen, entweder über eine sichtbare Überschrift mit aria-labelledby oder über aria-label.
  • Jeder Tab erhält role="tab", eine eindeutige, stabile id und aria-controls="panel-id", das auf das zugehörige Panel verweist.
  • Jedes Panel erhält role="tabpanel", eine eindeutige id und aria-labelledby="tab-id", das auf den steuernden Tab verweist.
  • Der aktive Tab hat aria-selected="true"; alle anderen Tabs haben aria-selected="false". Inaktive Panels werden beispielsweise mit dem Attribut hidden ausgeblendet.
  • Tabs verwenden roving tabindex: Der aktive Tab hat tabindex="0", alle anderen tabindex="-1". Ein Panel ohne fokussierbare Inhalte kann tabindex="0" erhalten, damit es in der Tastaturreihenfolge erreichbar ist.
  • Jeder Tab erhält eine eindeutige, stabile Kennung, die sicher in einem URL-Fragment verwendet werden kann, zum Beispiel #tab-id. Es werden URL-sichere Kennungen verwendet oder Werte beim Lesen des Hashes einheitlich kodiert und dekodiert.
  • Beim initialen Laden der Seite wird der Hash einem Tab zugeordnet. Wird ein passender Tab gefunden, werden dieser und sein Panel aktiviert; anschließend scrollt die Leiste zu diesem Tab. Bei einem unbekannten Hash bleibt der Standard-Tab aktiv.
  • Bei der Auswahl eines Tabs wird die URL entsprechend der gewählten History-Strategie aktualisiert. history.replaceState aktualisiert den aktuellen Eintrag, ohne für jede Auswahl einen eigenen Zurück-Schritt hinzuzufügen. Die Anwendung muss den Tab-Zustand im selben Handler aktualisieren und darf sich dafür nicht auf ein hashchange-Event verlassen.
  • Sollen Zurück und Vorwärts frühere Tab-Auswahlen wiederherstellen, wird history.pushState verwendet und der Tab-Zustand bei popstate synchronisiert.
  • Beim Aktualisieren des Hashes dürfen Pfad und Query-Parameter nicht entfernt werden. Bei einem unbekannten oder ungültigen Hash bleibt ein funktionsfähiger Standard-Tab ausgewählt.

Barrierefreiheit und Tastatur

  • tablist, tab und tabpanel werden nur für Tabs verwendet, die Panels auf derselben Seite umschalten. Für die Navigation zwischen Seiten werden Links verwendet, auch wenn sie wie Tabs gestaltet sind.
  • Mit Tab wird der Fokus auf den aktiven Tab in der Leiste gesetzt; das nächste Tab bewegt ihn aus der Tab-Liste zum Panel-Inhalt oder zum nächsten Seitenelement.
  • In einer horizontalen Liste bewegen ← und → den Fokus zwischen Tabs und springen am Listenende zum jeweils anderen Ende. In RTL-Oberflächen muss die Tastenrichtung der visuellen Reihenfolge und Leserichtung entsprechen.
  • Mit Home und End kann der Fokus zum ersten beziehungsweise letzten Tab springen. Bei manueller Aktivierung wird der fokussierte Tab mit Enter oder Space aktiviert; bei automatischer Aktivierung folgt die Auswahl dem Fokus.
  • Automatische Aktivierung wird verwendet, wenn das zugehörige Panel ohne merkliche Verzögerung angezeigt wird. Bei langsam ladenden Panels ist eine manuelle Aktivierung vorzuziehen, damit die Fokusbewegung keine verzögernden Vorgänge auslöst.
  • Bei einer Fokusbewegung wird der aktive Tab in den sichtbaren Bereich gescrollt. Der sichtbare Fokusindikator darf nicht vom Container abgeschnitten werden.

Prüfung

  • Bei mobiler Viewportbreite bleiben Tabs in einer Zeile, die Leiste lässt sich per Touch scrollen und das horizontale Scrollen erstreckt sich nicht auf die gesamte Seite.
  • Ein teilweise sichtbarer nächster Tab oder ein anderer Hinweis macht die Scrollmöglichkeit deutlich. Das Ausblenden der Scrollleiste darf keine verständliche Rückmeldung entfernen.
  • Der aktive Tab ist visuell und programmatisch gekennzeichnet; aria-selected, die Beziehungen aria-controls und aria-labelledby sowie die Sichtbarkeit der Panels bleiben synchron.
  • Die Tab-Liste hat einen zugänglichen Namen und jeder Tab eine verständliche Beschriftung; die Beziehungen werden mit einem Screenreader geprüft.
  • Die Tastaturnavigation entspricht dem gewählten Aktivierungsmodus, funktioniert an beiden Enden der Liste und berücksichtigt RTL.
  • Der ausgewählte Tab bleibt nach Klick, Tastaturnavigation und Laden über einen Hash sichtbar. Die Begrenzung der Zentrierung am Anfang und Ende der Liste wird geprüft.
  • Direkte Links mit gültigen und unbekannten Hashes werden beim initialen Laden und nach dem Neuladen der Seite geprüft.
  • Bei replaceState aktualisiert die Auswahl die Adresse, ohne für jeden Tab einen History-Eintrag anzulegen. Bei pushState synchronisieren Zurück und Vorwärts URL, aktiven Tab und Panel.
  • Die Scrollleiste wird nur ausgeblendet, wenn Touch- und Tastaturscrollen erhalten bleiben. Darstellung und Verhalten werden in den Zielbrowsern, einschließlich iOS und Android, geprüft.
  • Zentrierung und sanftes Scrollen dürfen Nutzer mit aktivierter Einstellung prefers-reduced-motion: reduce nicht beeinträchtigen.

Beispiele

Tab-Leiste mit Panels und ARIA-Beziehungen:

<div class="tabs__viewport">
  <div class="tabs__list" role="tablist" aria-label="Dokumentabschnitte">
    <button
      id="tab-overview"
      type="button"
      role="tab"
      aria-controls="panel-overview"
      aria-selected="true"
      tabindex="0"
    >
      Übersicht
    </button>
    <button
      id="tab-details"
      type="button"
      role="tab"
      aria-controls="panel-details"
      aria-selected="false"
      tabindex="-1"
    >
      Details
    </button>
  </div>
</div>

<section
  id="panel-overview"
  role="tabpanel"
  aria-labelledby="tab-overview"
  tabindex="0"
>
  Inhalt des Bereichs „Übersicht“.
</section>

<section
  id="panel-details"
  role="tabpanel"
  aria-labelledby="tab-details"
  tabindex="0"
  hidden
>
  Inhalt des Bereichs „Details“.
</section>

CSS für eine einzeilige scrollbare Leiste:

.tabs__viewport {
  overflow-x: auto;
  padding: 2px;
  scroll-behavior: smooth;
}

.tabs__list {
  display: flex;
  flex-wrap: nowrap;
  width: max-content;
  min-width: 100%;
}

.tabs__list [role="tab"] {
  flex: 0 0 auto;
  white-space: nowrap;
}

.tabs__list [role="tab"][aria-selected="true"] {
  border-block-end: 2px solid currentColor;
}

.tabs__list [role="tab"]:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

@media (max-width: 767px) {
  .tabs__viewport {
    scrollbar-width: none;
  }

  .tabs__viewport::-webkit-scrollbar {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .tabs__viewport {
    scroll-behavior: auto;
  }
}

Auf Mobilgeräten wird die ausgeblendete Scrollleiste durch einen teilweise sichtbaren nächsten Tab kompensiert. Der sichtbare Anteil hängt vom Container und den Beschriftungen ab; aktiver Tab und Fokusindikator bleiben vollständig sichtbar.

Der Breakpoint 767px im Media Query ist ein Beispiel und keine SST-A-Vorgabe. Er wird durch den in der responsiven Projektsystematik verwendeten Breakpoint ersetzt.

Tab zentrieren und URL synchronisieren:

const centerTab = (tab) => {
  tab.scrollIntoView({
    block: 'nearest',
    inline: 'center'
  })
}

const findTabFromUrl = (tabs) => {
  const tabId = window.location.hash.slice(1)

  return tabs.find((tab) => tab.id === tabId) || null
}

const updateTabUrl = (tab) => {
  window.history.replaceState(null, '', '#' + tab.id)
}

Bei der Initialisierung wird der über findTabFromUrl gefundene Tab zusammen mit seinem Panel aktiviert und an centerTab übergeben. Bei einer Benutzerauswahl werden zuerst aria-selected, roving tabindex und die Sichtbarkeit der Panels aktualisiert; danach werden centerTab und updateTabUrl aufgerufen. Dieses Beispiel zeigt die Synchronisierung von Zustand, URL und Scrollposition; Tastatur-Handler werden gemäß den obigen Regeln implementiert.

Ähnliche Kategorien:

Ähnliche Artikel

  • Aufbau einer React-Komponente

    Meine Vorstellung davon, wie jede React-Komponente aussehen sollte

    421

    8 min.

  • SSF-U – Einheitlicher Standard für Vollbildmodus

    Der SSF-U-Standard legt Anforderungen an die Semantik, Barrierefreiheit und Funktionslogik von Vollbildmodus fest

    248

    2 min.

  • SSA – Einheitlicher Standard für Akkordeons

    Der SSA-Standard legt Anforderungen an die Semantik, Barrierefreiheit und Funktionslogik von Akkordeons fest

    258

    2 min.

  • Bad Practices für Websites

    Analyse kritischer Fehler im Webdesign. Warum Slider, Autoplay und schwerfällige Seiten die Konversionsrate sowie die Platzierungen bei Google verschlechtern

    232

    2 min.

  • SSP - Einheitlicher Standard für Paginierung

    Der SSP-Standard legt Anforderungen an die Semantik, Barrierefreiheit und Funktionslogik von Paginierung fest

    240

    1 min.

  • SSPS – Einheitlicher Standard für Projektstruktur

    Der SSPS-Standard legt Anforderungen an die Struktur und Benennung von Dateien und Ordnern im Projekt fest

    345

    2 min.

  • Alle Artikel

Kontaktieren Sie mich