CSS Zähler
Zuletzt aktualisiert am 15. Februar 2026
CSS Zähler ermöglichen automatische Nummerierung ohne HTML-Listen. Mit counter-reset erzeugst du einen Zähler, mit counter-increment zählst du ihn hoch, und mit den Funktionen counter() und counters() gibst du den Wert über die content-Eigenschaft aus. So kannst du Überschriften, Abschnitte, Schritte oder beliebige Elemente durchnummerieren, ohne die Nummern manuell im HTML zu pflegen. Besonders mächtig wird es mit counters() für verschachtelte Nummerierungen wie 1.1, 1.2, 2.1.
counter-reset: <name> <integer>? none Grundlagen
CSS Zähler bestehen aus drei Teilen, die zusammenspielen:
counter-reseterstellt einen neuen Zähler und setzt ihn auf einen Startwert (Standard: 0). Du setztcounter-resetauf das Elternelement, das den Zählbereich definiert.counter-incrementerhöht den Zähler um einen Wert (Standard: 1). Du setzt es auf die Elemente, die gezählt werden sollen.counter()/counters()sind Funktionen, die du incontentverwendest, um den aktuellen Zählerwert auszugeben.counter()gibt einen einzelnen Wert aus,counters()sammelt alle verschachtelten Instanzen desselben Zählers mit einem Trennzeichen.
Ein typisches Beispiel: Du setzt counter-reset: section auf den <body>, counter-increment: section auf jedes <h2>, und content: counter(section) ". " auf h2::before. Schon werden alle <h2> automatisch durchnummeriert, und die Nummern aktualisieren sich automatisch, wenn du einen Abschnitt hinzufügst, entfernst oder umstellst.
Syntax & Werte
counter-reset
| Wert | Beschreibung | Beispiel |
|---|---|---|
none | Kein Zähler wird erstellt oder zurückgesetzt (Standard). | counter-reset: none |
<name> | Erstellt den Zähler mit dem Startwert 0. | counter-reset: section |
<name> <integer> | Erstellt den Zähler mit einem bestimmten Startwert. | counter-reset: section 5 |
<name1> <name2> | Mehrere Zähler gleichzeitig erstellen. | counter-reset: section step |
counter-increment
| Wert | Beschreibung | Beispiel |
|---|---|---|
none | Kein Zähler wird erhöht (Standard). | counter-increment: none |
<name> | Erhöht den Zähler um 1. | counter-increment: section |
<name> <integer> | Erhöht den Zähler um den angegebenen Wert. Negative Werte zählen rückwärts. | counter-increment: section 2 |
counter() und counters()
| Wert | Beschreibung | Beispiel |
|---|---|---|
counter(name) | Gibt den aktuellen Wert des Zählers als Dezimalzahl aus. | content: counter(section) |
counter(name, style) | Gibt den Wert im angegebenen Zählstil aus (z.B. upper-roman, lower-alpha). | content: counter(section, upper-roman) |
counters(name, string) | Sammelt alle verschachtelten Instanzen des Zählers mit einem Trennzeichen. | content: counters(section, ".") |
counters(name, string, style) | Verschachtelte Zähler mit Trennzeichen und Zählstil. | content: counters(section, ".", upper-roman) |
Beispiele
Automatische Abschnittsnummern
Überschriften automatisch durchnummerieren, ohne die Nummern im HTML zu schreiben.
body {
counter-reset: abschnitt;
}
h2 {
counter-increment: abschnitt;
}
h2::before {
content: counter(abschnitt) ". ";
color: #3b82f6;
}<div class="section-demo">
<h3>Einleitung</h3>
<p>Hier steht der einleitende Text zum Thema.</p>
<h3>Grundlagen</h3>
<p>Die Grundlagen werden in diesem Abschnitt erklärt.</p>
<h3>Fortgeschritten</h3>
<p>Weiterführende Konzepte und Techniken.</p>
<h3>Zusammenfassung</h3>
<p>Ein kurzes Fazit am Ende.</p>
</div>Eigene nummerierte Liste
Eine optisch ansprechende nummerierte Liste mit großen, farbigen Nummern, ganz ohne <ol>.
.list {
counter-reset: item;
}
.list-item {
counter-increment: item;
}
.list-item::before {
content: counter(item);
background: #3b82f6;
color: #fff;
border-radius: 50%;
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
}<div class="custom-list">
<div class="item"><div class="item-text"><strong>HTML-Grundgerüst erstellen</strong><br/>Erstelle die index.html mit Doctype und Grundstruktur.</div></div>
<div class="item"><div class="item-text"><strong>CSS einbinden</strong><br/>Verlinke dein Stylesheet im head-Bereich.</div></div>
<div class="item"><div class="item-text"><strong>Inhalt strukturieren</strong><br/>Verwende semantische Elemente wie header, main und footer.</div></div>
<div class="item"><div class="item-text"><strong>Styling anwenden</strong><br/>Gestalte Layout, Farben und Typografie mit CSS.</div></div>
</div>Verschachtelte Nummerierung
Mit counters() erzeugst du verschachtelte Nummerierungen wie 1.1, 1.2, 2.1. Jede neue Verschachtelungsebene erstellt eine eigene Instanz des gleichen Zählers.
ol {
counter-reset: nested;
list-style: none;
}
li {
counter-increment: nested;
}
li::before {
content: counters(nested, ".") " ";
color: #3b82f6;
font-weight: 700;
}<div class="nested-demo">
<ol>
<li>Einleitung
<ol>
<li>Motivation</li>
<li>Zielgruppe</li>
</ol>
</li>
<li>Grundlagen
<ol>
<li>HTML
<ol>
<li>Elemente</li>
<li>Attribute</li>
</ol>
</li>
<li>CSS
<ol>
<li>Selektoren</li>
<li>Box-Modell</li>
</ol>
</li>
</ol>
</li>
<li>Fortgeschritten
<ol>
<li>Flexbox</li>
<li>Grid</li>
</ol>
</li>
</ol>
</div>Verschiedene Zählstile
counter() akzeptiert als zweites Argument einen Zählstil. Damit kannst du römische Zahlen, Buchstaben oder andere Systeme verwenden.
/* Römische Zahlen */
li::before { content: counter(c, upper-roman) ". "; }
/* Kleinbuchstaben */
li::before { content: counter(c, lower-alpha) ") "; }
/* Führende Null */
li::before { content: counter(c, decimal-leading-zero) " "; }<div class="style-demo">
<div>
<h4>upper-roman</h4>
<ol class="st-roman"><li>Erster</li><li>Zweiter</li><li>Dritter</li><li>Vierter</li></ol>
</div>
<div>
<h4>lower-alpha</h4>
<ol class="st-alpha"><li>Erster</li><li>Zweiter</li><li>Dritter</li><li>Vierter</li></ol>
</div>
<div>
<h4>decimal-leading-zero</h4>
<ol class="st-leading"><li>Erster</li><li>Zweiter</li><li>Dritter</li><li>Vierter</li></ol>
</div>
</div>Schritt-für-Schritt Anleitung
CSS Zähler funktionieren auf beliebigen Elementen, nicht nur auf Listen. Hier werden <div>-Elemente als Schritte durchnummeriert.
.tutorial {
counter-reset: step;
}
.step {
counter-increment: step;
}
.step::before {
content: counter(step);
background: linear-gradient(135deg, #3b82f6, #7c3aed);
color: #fff;
width: 36px;
height: 36px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}<div class="steps-demo">
<div class="step">
<div class="step-content">
<h4>Repository klonen</h4>
<p>Klone das Projekt mit git clone auf deinen Rechner.</p>
</div>
</div>
<div class="step">
<div class="step-content">
<h4>Dependencies installieren</h4>
<p>Führe npm install im Projektverzeichnis aus.</p>
</div>
</div>
<div class="step">
<div class="step-content">
<h4>Entwicklungsserver starten</h4>
<p>Mit npm run dev startest du den lokalen Server.</p>
</div>
</div>
<div class="step">
<div class="step-content">
<h4>Loslegen</h4>
<p>Öffne localhost:4321 im Browser und beginne mit der Entwicklung.</p>
</div>
</div>
</div>Barrierefreiheit
Inhalte, die über ::before und content generiert werden, erscheinen nicht im DOM und sind für manche assistive Technologien nicht zugänglich. Screenreader lesen content-Text zwar inzwischen meist vor, aber das Verhalten ist nicht einheitlich. Verlasse dich daher nicht darauf, dass die generierten Nummern von allen Nutzern wahrgenommen werden.
Wenn die Nummerierung semantische Bedeutung hat (z.B. eine geordnete Reihenfolge), verwende <ol> statt CSS-Counter. <ol> vermittelt die Reihenfolge semantisch korrekt an Screenreader, während CSS-Counter rein visuell sind. CSS Zähler eignen sich besser für dekorative Nummerierungen, bei denen die Nummer eine optische Ergänzung ist, aber kein essentieller Inhalt.
Für Dokumentstrukturen wie Kapitel- und Abschnittsnummern sollte die Hierarchie über eine korrekte Heading-Struktur (<h1> bis <h6>) vermittelt werden, nicht allein über CSS-Counter. Die Counter-Nummern sind dann eine visuelle Hilfe, aber die eigentliche Struktur kommt aus dem HTML.
Häufige Fehler
counter-resetauf dem falschen Element:counter-resetmuss auf dem Elternelement stehen, nicht auf dem Element, das gezählt wird. Setzt ducounter-resetaufh2, wird der Zähler bei jedem<h2>zurückgesetzt, statt hochzuzählen.counter-incrementohnecounter-reset: Ohnecounter-resetexistiert der Zähler nicht. Der Browser erzeugt dann implizit einen Zähler, aber das Verhalten ist unzuverlässig und schwer nachzuvollziehen.counter()außerhalb voncontentverwenden:counter()undcounters()funktionieren nur innerhalb dercontent-Eigenschaft auf::beforeoder::after. Du kannst sie nicht direkt in Eigenschaften wiewidthodercolorverwenden.- Verschachtelte Zähler ohne
counter-resetpro Ebene: Bei verschachtelten Listen muss jede<ol>oder<ul>den Zähler zurücksetzen, damit jede Ebene ihren eigenen Zähler bekommt. Ohne das zählen alle Ebenen denselben Zähler weiter. - Reihenfolge von Increment und Content verwechseln:
counter-incrementwird angewendet, bevorcontentausgewertet wird. Der Zähler zeigt also den bereits erhöhten Wert an. Wenn du bei 1 starten willst, setzecounter-reset: name 0(Standard), nichtcounter-reset: name 1.
Browser-Kompatibilität
CSS Counter (counter-reset, counter-increment, counter(), counters()) werden seit über 20 Jahren von allen Browsern vollständig unterstützt.
| Client | Unterstützung | Hinweise |
|---|---|---|
| Chrome | Komplett | — |
| Firefox | Komplett | — |
| Safari | Komplett | — |
| Edge | Komplett | — |
| Opera | Komplett | — |
Email-Kompatibilität
CSS Counter werden von den meisten Email-Clients nicht unterstützt, da ::before/::after und content in Emails stark eingeschränkt sind.
| Client | Unterstützung | Hinweise |
|---|---|---|
| Apple Mail | Komplett | — |
| Gmail | Keine | content und ::before/::after werden entfernt |
| Outlook | Keine | Kein Support für Pseudo-Elemente oder content |
| Thunderbird | Komplett | — |
| Yahoo Mail | Keine | Pseudo-Elemente werden nicht unterstützt |
Verwandte Eigenschaften
Bleib auf dem Laufenden
Erhalte neue Inhalte direkt in dein Postfach
Was erwartet dich?
Neue Artikel & Videos
Wenn ich was Neues veröffentliche, erfährst du's hier zuerst.
Plattform & Kurs-Updates
Neue Kurse, Referenz-Updates und gelegentlich Sonderpreise zum Launch.
Einmal die Woche in deinem Postfach
Kurz, auf den Punkt, kein Spam.