Komponenten · Navigation & Bedienelemente

Pagination & „Mehr laden“

Eine barrierefreie Seitennavigation ist ein <nav> mit echten Links, bei dem die aktuelle Seite aria-current="page" trägt und sichtbar mehr als nur farblich markiert ist. „Mehr laden“ braucht darüber hinaus zwei Dinge, die man leicht vergisst: eine Ansage über eine Live-Region und einen Fokus, der zum neuen Inhalt wandert.

Lange Trefferlisten müssen aufgeteilt werden – die Frage ist nur, wie. Alle drei üblichen Muster lassen sich zugänglich bauen, aber sie starten von sehr unterschiedlichen Ausgangslagen, und eines davon hat eine Schattenseite, die man nicht wegprogrammieren kann.

Das Wichtigste in Kürze

  • Echte <a href> in der Pagination – kein href="#", kein javascript:void(0), keine Klick-<div>s.
  • Die aktuelle Seite bleibt ein Link mit echtem Ziel und bekommt aria-current="page". Genau ein Element pro Set.
  • Farbe allein reicht nicht: Die Markierung braucht ein zweites, nicht-farbliches Merkmal und mindestens 3:1 Kontrast – zum Hintergrund und zu den übrigen Seitenzahlen.
  • 24 × 24 CSS-Pixel Zielgröße als Untergrenze (2.5.8, Stufe AA) – Seitenzahlen sind hier notorische Sünder.
  • „Mehr laden“: erst ansagen, dann den Fokus verlagern. Ohne beides sind zehn neue Einträge da, von denen niemand erfährt.
  • SEO: eigene URL pro Seite, selbstreferenzierendes Canonical, keine #-Fragmente – und crawlbare Links hinter jedem Nachlade-Button.

Welches Muster wann?

Drei Spalten nebeneinander. Erstens Seitennavigation mit Zurück, den Seitenzahlen 1 bis 3 und Weiter, wobei die 2 hervorgehoben ist – sie erfüllt alle sechs geprüften Kriterien außer fortlaufendem Stöbern. Zweitens ein Mehr-laden-Button unter drei Listeneinträgen – eigene URL und Zurück-Button nur eingeschränkt, ohne JavaScript nicht nutzbar. Drittens Infinite Scroll als nach unten ausblendende Liste – nur fortlaufendes Stöbern erfüllt, alle fünf übrigen Kriterien nicht.
Dieselbe Aufgabe, drei Ausgangslagen. Die Seitennavigation bringt fast alles von Haus aus mit, Infinite Scroll muss jede Zeile davon nachbauen.

Die Entscheidung hängt weniger am Geschmack als an der Frage, was Nutzende vorhaben:

Situation Passendes Muster
Gezielt etwas suchen und finden Pagination
Treffer untereinander vergleichen Pagination
Eine bestimmte Position wiederfinden oder teilen Pagination
Ohne festes Ziel stöbern (Feed, Galerie) „Mehr laden“
Homogener Strom ohne Ende und ohne Ziel Infinite Scroll (mit Vorbehalt)
Suchmaschinen sollen alle Einträge finden Pagination oder crawlbare Links

Die Nielsen Norman Group rät ausdrücklich von Infinite Scroll ab, wenn Nutzende etwas Bestimmtes suchen, Einträge in einer langen Liste vergleichen wollen, mit geringer Bandbreite unterwegs sind – oder wenn viele Menschen mit Behinderungen zur Zielgruppe gehören.

Klassische Pagination: das Grundgerüst

Eine Seitennavigation ist eine Navigation mit einer Liste echter Links:

<nav aria-label="Seitennavigation">
  <ul>
    <li><span class="pg-aus">Zurück</span></li>
    <li><a href="?seite=1">Seite 1</a></li>
    <li><a href="?seite=2" aria-current="page">Seite 2</a></li>
    <li><a href="?seite=3">Seite 3</a></li>
    <li><a href="?seite=3">Weiter</a></li>
  </ul>
</nav>

Vier Entscheidungen stecken darin:

Das aria-label an der <nav>. Sobald es mehr als eine Navigation auf der Seite gibt, braucht jede einen eigenen Namen (2.4.6). „Seitennavigation“ ist gut; „Navigation Seitennavigation“ wäre doppelt gemoppelt, weil die Rolle ohnehin angesagt wird.

Die aktuelle Seite bleibt ein Link. Das ist kontraintuitiv – warum auf die Seite verlinken, auf der man schon ist? Die Begründung des US Web Design System ist pragmatisch: „Use a link for the current page for robustness.“ Wer per Screenreader durch die Elementliste springt, findet die aktuelle Seite dann zuverlässig als Link mit dem Zustand „aktuelle Seite“. Ein href="#" oder ein <span> an dieser Stelle nimmt diese Information weg.

<ul> oder <ol>? Beides ist vertretbar. Für reines Durchblättern spricht etwas für <ol>; sobald „Zurück“ und „Weiter“ mit in der Liste stehen, ist die Nummerierung eher irreführend. USWDS und das BBC-Designsystem nehmen <ul> – eine Pflicht zur Reihenfolge-Semantik gibt es nicht.

Wie viele Zahlen? USWDS legt maximal sieben Slots fest und hält diese Anzahl über alle Seiten des Sets konstant. Das ist keine Norm, aber eine gute Regel: Ein Layout, das je nach Seite zwischen fünf und elf Elementen springt, verschiebt bei jedem Klick die Klickziele.

aria-current="page" richtig einsetzen

aria-current markiert das Element innerhalb einer Gruppe, das gerade „dran“ ist. Es kennt genau sieben gültige Werte:

Wert Bedeutung
page aktuelle Seite in einer Seitennavigation
step aktueller Schritt in einem Prozess
location aktueller Ort, z. B. in einem Fortschrittsbalken
date aktuelles Datum in einem Kalender
time aktuelle Uhrzeit
true aktuelles Element ohne genauere Angabe
false nicht aktuell (wird nicht exponiert)

Zwei Fallstricke: Jeder andere nicht-leere Wert wird wie true behandelt – ein Tippfehler wie aria-current="pages" fällt also nicht auf false zurück, sondern erzeugt eine unpräzise Ansage. Und: Nur ein Element pro Gruppe darf markiert sein.

aria-current="page" ist dabei kein Ersatz für die sichtbare Kennzeichnung – sondern deren Gegenstück für Hilfsmittel.

Sichtbar machen: 3:1 statt nur Farbe

Die Handreichung der Überwachungsstelle des Bundes für Barrierefreiheit von Informationstechnik (BFIT-Bund) ist hier ungewöhnlich konkret. Anforderung 817 (Muss): „Die Markierung für die aktuelle Seite muss zum Hintergrund sowie den sonstigen Seiten ein Kontrastverhältnis von mindestens 3:1 aufweisen.“

Das sind zwei Messungen, nicht eine: Die Markierung muss sich vom Hintergrund abheben und von den anderen Seitenzahlen. Dazu kommt 1.4.1 Benutzung von Farbe: Farbe allein darf nicht das einzige Unterscheidungsmerkmal sein.

/* Nicht ausreichend: nur Farbe */
.pg [aria-current="page"] { color: #2563eb; }

/* Ausreichend: Fläche, Form und Schriftschnitt kommen dazu */
.pg [aria-current="page"] {
  background: #2563eb;
  color: #fff;
  border-radius: 0.5rem;
  font-weight: 700;
  text-decoration: none;
}

Nachmessen kannst du das mit dem Kontrast-Check; die Hintergründe stehen unter Farbkontraste.

Zugängliche Namen für Zahlen, Pfeile und Icons

Eine „3“ allein ist kein guter Linkname. Zwei Wege führen laut BFIT-Bund (Anforderung 821) zum Ziel: Entweder der zugängliche Name wird ergänzt – oder die Schalter liegen in einer Gruppe, die als „Paginierung“ beschriftet ist.

Wenn du ergänzt, dann mit visuell verstecktem Text statt mit aria-label:

<li>
  <a href="?seite=3">
    <span class="visually-hidden">Seite </span>3
  </a>
</li>

<li>
  <a href="?seite=3">
    <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24" width="16" height="16">
      <path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2"/>
    </svg>
    Weiter<span class="visually-hidden">, Seite 3</span>
  </a>
</li>
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

Warum nicht einfach aria-label="Seite 3"? Der spezifikationsgestützte Grund ist 2.5.3 Beschriftung im Namen: Wer per Sprache bedient, sagt „Klick 3“ – und dafür muss der sichtbare Text im zugänglichen Namen enthalten sein. aria-label ersetzt den sichtbaren Text dagegen komplett. Dazu kommt eine praktische Beobachtung aus dem HTMHell-Adventskalender (getestet im Dezember 2024 mit NVDA 2024.4 und Chrome 130): Englischer Text in einem aria-label wurde mit deutscher Stimme vorgelesen, während Text aus einer .sr-only-Klasse korrekt ausgesprochen wurde. Ein Einzeltest, kein Spezifikationsverhalten – aber ein weiterer Grund, dem sichtbaren Text den Vorzug zu geben.

Und ein handfester Fehler zum Schluss: aria-label wirkt nicht auf Elementen ohne Rolle. <span aria-label="Seite 3">3</span> ist wirkungslos – das ist eine ARIA-Regel, kein Browser-Bug.

Auslassungspunkte: „…“ wird nicht vorgelesen

Bei langen Sets stehen zwischen den Zahlen Auslassungspunkte. Screenreader sagen „…“ in der Regel nicht an – die Information, dass Seiten übersprungen wurden, geht damit verloren.

<li>
  <span aria-hidden="true">…</span>
  <span class="visually-hidden">Seiten 4 bis 9 übersprungen</span>
</li>

Wichtig: Das Overflow-Element ist kein Link und kein Button. Es ist ein Hinweis, kein Bedienelement.

Deaktivierte „Zurück“- und „Weiter“-Elemente

Auf der ersten Seite gibt es kein „Zurück“. Die verbreitete Lösung – ein <a>, das per CSS ausgegraut wird, aber weiter verlinkt – ist die schlechteste: Sie sieht deaktiviert aus und funktioniert trotzdem.

<!-- Falsch: sieht deaktiviert aus, ist es aber nicht -->
<li><a href="?seite=0" class="deaktiviert">Zurück</a></li>

<!-- Richtig: gar kein Bedienelement -->
<li><span class="pg-aus">Zurück</span></li>

Ein <span> ist hier die sauberste Lösung: kein Link, keine Rolle, kein Fokusziel, kein ARIA. Die manchmal empfohlene Variante <a role="link" aria-disabled="true"> ohne href hat einen Haken – ein <a> ohne href ist nicht fokussierbar, die Ansage „deaktiviert“ erreicht Tastaturnutzende also gar nicht erst. Und aria-disabled ist ohnehin rein semantisch: Es verhindert nichts, es sagt nur etwas an.

Klickfläche: 24 × 24 CSS-Pixel

2.5.8 Zielgröße (Minimum) verlangt seit WCAG 2.2 auf Stufe AA mindestens 24 × 24 CSS-Pixel für Klickziele. Gemeint ist die klickbare Fläche – Padding zählt mit, die Schriftgröße allein tut es nicht.

.pg a,
.pg .pg-aus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 2.75rem;
  min-block-size: 2.75rem;
  padding-inline: 0.5rem;
}

Fünf Ausnahmen gibt es (Spacing, Equivalent, Inline, User Agent Control, Essential). Für Paginierungen greift praktisch nur die erste: Sie erlaubt kleinere Ziele, wenn ein Kreis von 24 CSS-Pixeln Durchmesser, zentriert auf dem Ziel, kein anderes Ziel und keinen anderen solchen Kreis schneidet – man erkauft die kleine Fläche also mit Abstand. Die BFIT-Bund-Handreichung führt die 24 px als Soll; über WCAG 2.5.8 und die EN 301 549 sind sie im BITV-Kontext trotzdem verbindlich.

Tastatur und Fokus

Drei Muss-Anforderungen der BFIT-Bund-Handreichung, die im Alltag zählen: Die Seitennavigation muss mit der Tastatur erreicht, bedient und wieder verlassen werden können (818), sie darf beim Fokussieren keine unerwarteten Kontextwechsel auslösen (819a), und der Fokus darf beim Blättern nicht verloren gehen (819b).

Der letzte Punkt ist der, der in der Praxis kippt: Wer auf „Weiter“ klickt und die Seite lädt neu, landet am Seitenanfang – das ist in Ordnung. Wer aber per JavaScript nachlädt und den Fokus nicht mitführt, verliert ihn an <body>, und die Tastatur beginnt wieder ganz oben.

Dazu kommt der sichtbare Fokus (2.4.7) und – bei klebenden Kopf- oder Fußleisten – 2.4.11 Fokus nicht verdeckt:

.pg a:focus-visible {
  outline: 3px solid #0b3d91;
  outline-offset: 2px;
  scroll-margin-block: 6rem; /* damit ein Sticky-Header ihn nicht verdeckt */
}

Optional, aber freundlich: Bild auf / Bild ab für vorherige und nächste Seite, Pos1 / Ende für die erste und letzte. Die BFIT-Bund-Handreichung empfiehlt das, verlangt es aber nicht – und ungewohnte Tastenbelegungen muss man dokumentieren, sonst findet sie niemand.

„Mehr laden“: das vollständige Beispiel

Der solideste Weg ist Progressive Enhancement: Serverseitig ausgelieferte Pagination als Fundament, per JavaScript zum Button aufgewertet. Ohne JavaScript bleibt die Pagination stehen – so macht es auch das BBC-Designsystem.

<ul id="treffer">
  <li>…</li>
</ul>

<p id="stand" role="status"></p>

<nav aria-label="Seitennavigation" id="pagination">
  <ul>
    <li><a href="?seite=2">Seite 2</a></li>
  </ul>
</nav>

<button type="button" id="mehr" hidden data-naechste="2">Weitere 10 laden</button>

Die Live-Region (<p id="stand" role="status">) steht leer und von Anfang an im DOM. Eine Live-Region, die erst zur Laufzeit eingefügt wird, sagt typischerweise gar nichts an.

const liste = document.getElementById('treffer');
const button = document.getElementById('mehr');
const stand = document.getElementById('stand');
const pagination = document.getElementById('pagination');

// Progressive Enhancement: erst jetzt tauschen wir Pagination gegen Button
pagination.hidden = true;
button.hidden = false;

button.addEventListener('click', async () => {
  const seite = Number(button.dataset.naechste);

  button.setAttribute('aria-disabled', 'true');
  liste.setAttribute('aria-busy', 'true');
  stand.textContent = 'Wird geladen, bitte warten';

  const antwort = await fetch(`/api/treffer?seite=${seite}`);
  const daten = await antwort.json();

  // Trenner vor der neuen Charge – er wird gleich das Fokusziel
  const trenner = document.createElement('li');
  trenner.tabIndex = -1;
  trenner.className = 'charge-trenner';
  trenner.textContent = `Ergebnisse ${daten.von} bis ${daten.bis}`;
  liste.append(trenner);

  for (const eintrag of daten.eintraege) {
    liste.insertAdjacentHTML('beforeend', eintrag.html);
  }

  liste.setAttribute('aria-busy', 'false');
  button.removeAttribute('aria-disabled');
  stand.textContent = `${daten.eintraege.length} weitere geladen. ${daten.bis} von ${daten.gesamt}.`;

  history.replaceState(null, '', `?seite=${seite}`);
  trenner.focus();

  if (daten.bis >= daten.gesamt) {
    button.remove();
    stand.textContent = `Alle ${daten.gesamt} Ergebnisse geladen.`;
  }
});
Vier nummerierte Schritte. Erstens Vorher: drei Listeneinträge und ein fokussierter Button „Weitere 10 laden“. Zweitens Beschäftigt: der Button ist grau und zeigt „Lädt …“, eine Ansage meldet dasselbe. Drittens Ansage: zwei neue grüne Einträge sind angehängt, die Ansage lautet „10 weitere Ergebnisse geladen. 30 von 120.“ Viertens Fokus: der erste neue Eintrag trägt den Fokusrahmen, der Button steht wieder bereit. Darunter ein roter Hinweis, dass ohne Schritt 3 und 4 niemand vom Nachladen erfährt.
Anhängen ist der einfache Teil. Ohne Schritt 3 und 4 wirkt der Klick für Screenreader-Nutzende wie ein Fehlklick – und wird prompt wiederholt.

Ein Detail mit Folgen: aria-disabled="true" statt disabled. Ein natives disabled nimmt dem Button den Fokus weg – und der Fokus landet dann irgendwo. aria-disabled sagt den Zustand an und lässt den Fokus, wo er ist; die Wirkung muss man im Handler selbst unterbinden.

Statusmeldungen: role="status", aria-live und aria-busy

Drei Begriffe, die gern verwechselt werden:

  • role="status" ist eine Live-Region mit implizitem aria-live="polite" und aria-atomic="true". Für Ladezustände und Ergebnismeldungen ist das die richtige Wahl.
  • aria-live="assertive" oder role="alert" unterbricht die laufende Ausgabe. Für „10 weitere geladen“ ist das übergriffig – nimm es für Fehler, nicht für Fortschritt.
  • aria-busy="true" am Container sagt: „Ich verändere mich gerade, lies mich noch nicht vor.“ Danach zwingend zurück auf false.

Das ist die praktische Umsetzung von 4.1.3 Statusmeldungen (Stufe AA). Mehr dazu unter Live-Regionen.

Und der Mythos gleich mit: Screenreader lesen nicht automatisch vor, was ins DOM kommt. Ohne Live-Region oder Fokusverlagerung passiert schlicht nichts.

Wohin gehört der Fokus?

Drei Strategien sind im Umlauf:

Strategie Stärke Schwäche
(a) Erster neuer Eintrag mit tabindex="-1" einfach, führt direkt weiter kein Kontext: „Woher weiß ich, dass hier Neues beginnt?“
(b) Trenner vor der Charge, der „Ergebnisse 11 bis 20“ ansagt Kontext kommt mit, robust ein zusätzliches Element im Markup
(c) Fokus bleibt am Button, nur Ansage kein Fokussprung man muss rückwärts tabben, um zum Neuen zu kommen

Ich halte (b) für die beste Wahl – das ist auch das Muster des BBC-Designsystems. Der Trenner bekommt tabindex="-1" (nicht 0: Er soll nicht dauerhaft in der Tab-Reihenfolge liegen) und ein eigenes Fokus-Styling, das ihn nicht wie ein Bedienelement aussehen lässt – aber ganz ohne sichtbare Rückmeldung darf er auch nicht bleiben.

URL, History und der Zurück-Button

Das am häufigsten übersehene Problem: Wer dreimal „Mehr laden“ drückt, einen Treffer öffnet und zurückgeht, steht wieder bei den ersten zehn. Ein Baymard-Benchmark der 50 größten US-Shops stellte schon 2016 fest, dass über 90 % der Sites mit „Mehr laden“-Button genau das falsch machten. Die Zahl ist alt – das Problem begegnet mir bis heute in fast jedem zweiten Shop.

  • history.replaceState() beim Nachladen weiterer Chargen – sie sollen keine eigenen History-Einträge erzeugen.
  • history.pushState() nur bei echter Seitennavigation.
  • Immer echte Query-Parameter (?seite=3), niemals Fragmente (#seite=3): Google ignoriert Fragment-Identifier und folgt Links, die sich nur nach dem # unterscheiden, unter Umständen gar nicht.
  • Beim Zurückkommen die Position wiederherstellen – oder wenigstens die bereits geladene Anzahl.

Infinite Scroll: die Probleme im Detail

Automatisches Nachladen beim Scrollen ist kein WCAG-Verstoß an sich – es gibt kein Erfolgskriterium „kein Infinite Scroll“. Die Verstöße entstehen an ganz bestimmten Stellen, und sie treffen unterschiedliche Gruppen unterschiedlich hart. Deque hat neun betroffene Gruppen benannt; besonders eindeutig ist der Befund zur Spracheingabe: Nutzende von Dragon oder anderer Spracherkennungssoftware seien „completely left out of the infinite scroll experience“, weil es schlicht keinen Befehl gibt, mit dem sich das Nachladen auslösen ließe.

Betroffen Was konkret passiert
Spracheingabe Kein auslösbarer Befehl – Nachladen ist nicht bedienbar
Tastatur Der Tab-Pfad wächst unkontrolliert, der Fußbereich rückt weg
Screenreader Neue Inhalte werden ohne Live-Region gar nicht angesagt
Switch-Bedienung Jeder zusätzliche Eintrag verlängert die Scanzeit
Bildschirmvergrößerung Orientierung geht verloren, weil der Kontext springt
Kognition „Illusion of Completeness“ – man weiß nie, ob man fertig ist
Alle Strg+F findet nur, was bereits geladen ist

Dazu die harten Nebenwirkungen: Der Fußbereich wird unerreichbar, weil ständig Neues nachrückt, und die Position geht verloren, sobald man einen Eintrag öffnet und zurückkommt.

Sauber zugeordnet verletzt schlecht gebauter Infinite Scroll typischerweise 4.1.3 (keine Ansage), 2.4.3 (Fokus geht verloren) und 2.1.1 (nicht per Tastatur auslösbar) – bei automatischem Nachladen ohne Anforderung zusätzlich 3.2.5 (Stufe AAA).

role="feed": das ARIA-Muster, ehrlich eingeordnet

Für endlose Listen gibt es ein eigenes ARIA-Muster. Es ist gut gemeint, und man sollte es kennen – aber ich empfehle es nur mit Vorbehalt.

<div role="feed" aria-labelledby="feed-titel" aria-busy="false">
  <h2 id="feed-titel">Neueste Beiträge</h2>

  <article tabindex="0" aria-labelledby="p1-titel" aria-describedby="p1-text"
           aria-posinset="1" aria-setsize="-1">
    <h3 id="p1-titel">Barrierefreie Formulare</h3>
    <p id="p1-text">…</p>
  </article>
</div>
  • aria-setsize="-1" bedeutet „Gesamtzahl unbekannt“ – bei endlosen Listen der Normalfall.
  • aria-busy vor dem Einfügen auf true, danach auf false.
  • Tastatur: Bild ab = nächster Artikel, Bild auf = vorheriger, Strg+Ende = erstes fokussierbares Element nach dem Feed, Strg+Pos1 = erstes davor.

Und jetzt die Einschränkungen, die man dazusagen muss: Diese Tastenbelegung hat kein Vorbild aus Desktop-Oberflächen – niemand erwartet sie, also muss man sie auf der Seite dokumentieren. Sie kollidiert mit Widgets innerhalb der Artikel, die dieselben Tasten belegen. Und belastbare, aktuelle Aussagen zur Screenreader-Unterstützung sind rar: Die meistzitierte Supportmatrix von Deque stammt aus dem Jahr 2019 und listet noch Internet Explorer. Wer heute role="feed" einsetzt, sollte selbst testen.

Zwei Regeln aus der Praxis kommen dazu: keine Artikel mitten im Feed einfügen oder entfernen, und neue Artikel laden, bevor das Ende erreicht ist.

Den Fußbereich erreichbar halten

Wenn Infinite Scroll gesetzt ist, muss der Fußbereich trotzdem erreichbar bleiben. Drei Bausteine helfen:

<a class="skip" href="#fuss">Zum Fußbereich</a>

<button type="button" id="autoload" aria-pressed="true" class="autoload-schalter">
  Automatisches Nachladen: an
</button>

<div role="feed" aria-labelledby="feed-titel">…</div>

<footer id="fuss" tabindex="-1">…</footer>

Der Schalter ist ein Vorschlag von Deque: Er steht unmittelbar vor der Feed-Region, ist normalerweise visuell versteckt und wird bei Tastaturfokus sichtbar. Im Aus-Zustand erscheinen stattdessen „Mehr laden“- oder Pagination-Links. Mehr zum Sprunglink-Muster unter Skip-Links.

SEO: was Google dokumentiert

Der SEO-Teil ist bemerkenswert eindeutig – Google hat dazu eine eigene Dokumentationsseite, und fast alles darin widerspricht dem, was man in Foren liest.

  • Jede Seite braucht eine eigene URL (?seite=2). Ohne eigene URL gibt es nichts zu indexieren.
  • Selbstreferenzierendes Canonical je Seite – Seite 2 kanonisiert auf Seite 2, nicht auf Seite 1. Der verbreitete Rat, alles auf Seite 1 zu kanonisieren, ist falsch; mehr dazu unter Canonical & Duplicate Content.
  • Kein noindex auf paginierten Seiten. Sonst verwaisen die Detailseiten, die nur von dort verlinkt sind. noindex ist etwas für Filter- und Sortiervarianten.
  • rel="next"/rel="prev" wertet Google nicht mehr aus. Sie sind weiterhin gültige HTML-Linktypen und andere Suchmaschinen können sie nutzen – als Google-SEO-Maßnahme bringen sie nichts.
  • Keine #-Fragmente als Seitenzähler.
  • Crawler klicken keine Buttons. Googlebot rendert zwar JavaScript, löst aber keine Funktionen aus, die eine Nutzeraktion erfordern. Hinter „Mehr laden“ und Infinite Scroll gehören deshalb zusätzlich crawlbare <a href>-Links auf die paginierten URLs – im einfachsten Fall die Pagination selbst, die per JavaScript nur versteckt statt entfernt wird.
  • Titles und Descriptions dürfen auf paginierten Seiten ausnahmsweise identisch sein; die Empfehlung eindeutiger Titel gilt hier nicht.

Welche Kriterien hier greifen

Kriterium Stufe Bezug zur Pagination
1.4.11 Nicht-Text-Kontrast AA Markierung der aktuellen Seite, Fokusindikator
2.1.1 Tastatur A Blättern und Nachladen ohne Maus
2.4.3 Fokus-Reihenfolge A Fokus nach dem Nachladen
2.4.6 Überschriften und Beschriftungen AA Name der <nav>, Namen der Links
2.4.7 Fokus sichtbar AA sichtbarer Fokusindikator
2.4.11 Fokus nicht verdeckt AA Sticky-Leisten über der Pagination
2.5.8 Zielgröße AA 24 × 24 CSS-Pixel je Seitenzahl
4.1.3 Statusmeldungen AA Ansage nach „Mehr laden“

Die BFIT-Bund-Handreichung ordnet dieselben Punkte den EN-301-549-Klauseln zu – 9.1.4.11 (Kontrast), 9.2.1.1/9.2.1.2 (Tastatur), 9.2.4.3 (Fokusreihenfolge), 9.2.4.6 (Namen) und 9.4.1.2 (Rollen und Zustände).

Testen

  • Nur mit Tab durch die Pagination – auch auf der ersten und letzten Seite.
  • Sprachsteuerung: „Klick Seite 3“ – prüft 2.5.3 in einem Schritt.
  • Screenreader (NVDA mit Firefox oder Chrome, VoiceOver auf macOS und iOS): Wird die aktuelle Seite angesagt? Kommt nach „Mehr laden“ eine Meldung?
  • Zoom auf 400 % (1.4.10 Reflow): Bleibt die Pagination bedienbar oder wird sie zur Wurstkette?
  • Zurück-Button nach dem Nachladen.
  • JavaScript aus: Steht die Pagination noch?

Häufige Fehler

  • Klick-<div>s statt echter Links – nicht fokussierbar, nicht teilbar.
  • Aktuelle Seite nur farblich markiert, ohne zweites Merkmal und ohne aria-current="page".
  • aria-label, das den sichtbaren Text nicht enthält – sabotiert die Sprachsteuerung.
  • Deaktivierte Blätter-Links mit href, die trotz Ausgrauen funktionieren.
  • „…“ ohne Erläuterung – wird nicht vorgelesen.
  • „Mehr laden“ ohne Ansage oder ohne Fokusverlagerung.
  • Live-Region erst zur Laufzeit eingefügt – sie sagt dann nichts.
  • disabled statt aria-disabled am Ladebutton: Der Fokus geht verloren.
  • #-Fragmente als Seitenzähler oder Canonical aller Seiten auf Seite 1.
  • Infinite Scroll ohne Abschaltmöglichkeit und ohne erreichbaren Fußbereich.

Häufige Fragen

Braucht die aktuelle Seite wirklich noch ein href?

Ja, das ist die robustere Variante. Screenreader-Nutzende springen häufig über die Linkliste; ein <span> an dieser Stelle fällt dort heraus. Der Link zeigt auf die eigene URL und trägt aria-current="page".

Soll ich rel="next" und rel="prev" noch setzen?

Es schadet nicht, bringt bei Google aber nachweislich nichts. Wenn dein CMS sie ohnehin ausgibt, lass sie stehen; extra einbauen musst du sie nicht.

Ist role="feed" produktionsreif?

Ich würde es heute nur mit eigenem Test einsetzen. Die Tastaturkonventionen sind ungewohnt und dokumentationspflichtig, sie kollidieren mit Bedienelementen in den Artikeln, und aktuelle Aussagen zum Screenreader-Support fehlen. Für die meisten Listen ist „Mehr laden“ die verlässlichere Wahl.

Wie viele Seitenzahlen zeige ich?

Sieben Slots sind ein guter Richtwert – und vor allem: immer gleich viele, damit die Klickziele beim Blättern nicht wandern.

Darf „Mehr laden“ automatisch beim Scrollen auslösen?

Dann ist es kein Button mehr, sondern Infinite Scroll – mit allen Folgen. Wer beides kombinieren will, sollte das automatische Nachladen abschaltbar machen.

Pagination oder „Mehr laden“?

Pagination, wenn man gezielt springen, vergleichen und URLs teilen können soll – das ist auch fürs SEO der ruhigere Weg. „Mehr laden“ für fortlaufendes Stöbern. Beide sind zugänglich zu bauen.

Fazit

Pagination baust du als <nav> mit echten Links, aria-current="page" und einer Markierung, die mehr kann als Farbe. „Mehr laden“ ist nur so gut wie sein Nachspiel: role="status"-Ansage, Fokus auf einen Trenner vor der neuen Charge, replaceState für die URL – und crawlbare Links dahinter, damit Suchmaschinen überhaupt weiterkommen. Infinite Scroll bleibt der heikelste Weg; wenn er sein muss, dann mit Abschalter, erreichbarem Fußbereich und der ehrlichen Erkenntnis, dass ein Teil der Nutzenden ihn gar nicht bedienen kann. Im Zweifel: der bewusst ausgelöste Button.

Quellen

Gratis E-Book PDF Das Praxishandbuch

Kostenloses E-Book

Das Praxishandbuch für sauberes, zugängliches Web

Alles rund um semantisches HTML, Barrierefreiheit, WCAG & BFSG, GEO und SEO — praxisnah und am echten Code. In mehreren Feedbackschleifen von Leserinnen und Lesern verbessert.

  • 3.000+ Downloads
  • 7. Auflage
  • 37 Seiten
  • PDF

Kein Spam. Abmeldung jederzeit mit einem Klick möglich.