HTML/Tutorials/Listen/Hybride Nummerierung

Aus SELFHTML-Wiki
< HTML‎ | Tutorials‎ | Listen(Weitergeleitet von Counters())
Wechseln zu: Navigation, Suche

Listen sind ein praktisches und oft verwendetes Mittel zur Darstellung von Informationen, wie z. B. Inhaltsverzeichnissen. Mit Hilfe von HTML ist es zwar möglich, auch die Nummerierung von Listen zu bestimmen, jedoch sind die Grenzen dabei bald erreicht, wenn es um eine hybride, also um eine gemischte Art der Nummerierung geht, bei der verschiedene Aufzählungsformate gemischt werden müssen.[1][2]

CSS schafft hier Abhilfe durch die Möglichkeit, eigene Zähler zu definieren, zu verändern und sie mit der counter()-Funktion in automatisch generierte Inhalte einzufügen. Die Erstellung solcher Zähler ist Teil des Seitenlayouts, so dass sie jedesmal, wenn die Seite neu aufgebaut wird, mit aktualisiert werden.[3]

Bereits im vorherigen Kapitel wurde für Listen der vordefinierte list-item-Zähler erwähnt:

Listennummerierung mit counter(list-item) ansehen …
ul {
   list-style-type: lower-latin;
}
li {
  padding-left: 0.5em;
}
li::marker {
  content: '(' counter(list-item) ')  ';
  color: red;
}

Listenelemente (<li>) werden vom Browser automatisch durchgezählt.

  • Bei sortierten Listen (<ol>) erscheint diese Zählung von selbst,
  • bei <ul> können sie in einem ::marker-Pseudoelement in der content-Eigenschaft sichtbar gemacht werden.

In diesem Tutorial zeigen wir, dass auch andere Elemente so durchgezählt werden können:

Was ist ein Zähler

CSS-Zähler sind von CSS verwaltete „Variablen“, deren Werte durch CSS-Regeln erhöht werden können (um zu verfolgen, wie oft sie verwendet werden). Mit tr:nth-of-type(odd) lässt sich beispielsweise jede zweite Tabellenzeile auswählen und entsprechend gestalten. CSS-Zähler zählen dagegen intern und geben dann diesen Zahlwert aus, um z.B. die Reihenfolge im Dokument anzuzeigen. Anders als bei ol müssen die gezählten Elemente aber nicht direkt aufeinander folgen.

Die Eigenschaft counter-reset erstellt einen Zähler:

Definieren eines Zählers
body {
   counter-reset: abschnitt 0;
}

Der Name muss ein gültiger CSS-Name sein. Der Wert muss eine Ganzzahl sein und ist optional. Wird er weggelassen, wird der Zähler auf 0 gesetzt und die Zählung beginnt dann bei 1.

Zähler sind immer einem HTML Element zugeordnet und sind dann für dessen Kindelemente sowie für seine nachfolgenden Geschwisterelemente und deren Kindelemente verfügbar.

Mehrere Zähler definieren
h1 {
   counter-reset: abschnitt 0 gruppe 3;
}

Um für ein Element mehr als einen Zähler zu erzeugen, gibt man hinter counter-reset mehrere Name-Wert Paare an.
Mehrere counter-reset Angaben würden - wie bei allen CSS-Eigenschaften - von der letzten Angabe überschrieben.


Zähler verändern

Der oben definierte Zähler kann mit den CSS-Eigenschaften counter-increment oder counter-set um einen bestimmten Wert verändert oder auch auf einen neuen Wert gesetzt werden.

Verändern eines Zählers
section {
   counter-increment: abschnitt 1;
}

Der Zähler abschnitt wird bei jeder section um 1 höher gezählt. Die Angabe eines Wertes bei counter-increment ist ebenfalls optional. Ohne Angabe verwendet CSS die 1.

Anstatt einen Zähler um einen bestimmten Wert zu verändern, kann man ihm auch einen neuen Wert zuweisen. Dazu dient die Eigenschaft counter-set:

Setzen des Wertes für einen Zähler
h1 {
   counter-set: count2 0;
}

Die Eigenschaften counter-reset und counter-set scheinen auf den ersten Blick das Gleiche zu tun. Auf die Unterschiede gehen wir ein, wenn wir Gültigkeitsbereiche und Vererbung von Zählern diskutieren.

Zählerwert anzeigen

Für die Anzeige eines Zählerinhalts nutzt CSS die content-Eigenschaft, die in Pseudoelementen wie ::before, ::after oder ::marker verwendet werden kann, und darin die CSS-Funktion counter() (engl. für Zähler), um den Inhalt eines Zählers abzurufen.

Artikel nummerieren ansehen …
body {
	counter-reset: abschnitt;
}

section {
	counter-increment: abschnitt;
}
section h2:before {
	content: counter(abschnitt);
}

Im body wird ein CSS-Counter abschnitt festgelegt, der alle section-Element zählt.

Vor jeder h2-Überschrift in den section-Elementen wird der Wert des Zählers über die counter()-Funktion ausgegeben.

Syntax counter(name, <list-style-type>)

  • name: Der Name des Zählers, dessen Wert auszugeben ist.
  • list-style-type ist ein optionaler Parameter, der die Darstellung der Durchnummerierung festlegt.
    CSS verwendet intern Ganzzahlen, aber für die Ausgabe können wie bei einer Listennummerierung auch römische Zahlen, Buchstaben oder auch selbst definierte Symbollisten verwendet werden.

Geschachtelte Zähler

Man kann auch mehrere Zähler kombinieren, um verschachtelte Zähler zu erzeugen:

Kapitelnummerierung ansehen …
body {
	counter-reset: kapitel 0 abschnitt 0;
	h2 {
		counter-increment: kapitel 1;
		counter-set: abschnitt 0;
	}
	h2::before {
		content: counter(kapitel) ' ';
		color: red;
	}
	h3 {
		counter-increment: abschnitt 1;
	}
	h3::before {
		content: counter(kapitel) '.' counter(abschnitt, lower-alpha) ' ';
		color: blue;
	}
}

Das Beispiel erzeugt die Zähler kapitel und count2 auf dem <body>-Element. Damit sind sie im ganzen HTML Dokument sichtbar. Würde man sie auf den h2 oder h3 Elementen definieren, könnte die Verwendung von <section> oder <article>-Elementen die Zählung stören. Darauf gehen wir noch ein, wenn es um Vererbung von Zählern geht.

Der kapitel-Zähler wird in jeder h2-Überschrift um 1 erhöht. Der abschnitt -Zähler wird je h2 wieder auf 0 gesetzt und in jeder h3-Überschrift erhöht, so dass die Kapitel (h2) über das ganze Dokument nummeriert werden und die Nummerierung der Abshcnitte (<h3>) Elemente mit jeder Kapitel-Überschrift erneut beginnt.

Um die Nummerierung darzustellen, bekommen die h2- und h3-Elemente jeweils ein ::before-Pseudoelement hinzugefügt. Als Inhalt erhält dieses Pseudoelement in h2-Überschriften den Inhalt von kapitel.

In h3-Überschriften wird der aktuelle Wert von kapitel, ein Punkt und dann der Wert von abschnitt ausgegeben. Der Wert von abschnitt wird aber nicht als Zahl ausgegeben, sondern als Kleinbuchstabe. An die Nummerierung wird dann noch eine Leerstelle angefügt, damit sie den richtigen Abstand vom Überschriftentext bekommt.

Auf diese Weise werden die Überschriften nun als "1", "1.a", "1.b", "2" und "2.b" durchnummeriert. Öffne das Beispiel gerne einmal mit [Live ausprobieren] und teste, was geschieht, wenn man hinter den Zählernamen in counter-increment einen anderen Wert als 1 setzt.

Hinweis:
Das Beispiel verwendet zur Zählung h2 und h3. Webseiten verwenden üblicherweise nur ein h1-Element, das daher auch nicht durchgezählt werden muss.

dynamisch erstelltes Inhaltsverzeichnis

Häufig wird so eine verschachtelte Kapitelzählung wie im letzten Abschnitt auch in einem Inhaltsverzeichnis aufgenommen, um am Seitenanfang interne Links auf die jeweiligen Kapitel zu richten.

In Content Management Systemen wie unserem Wiki werden diese Inhaltsverzeichnissse dynamisch erstellt.[4] Diese Komfort-Funktion wollen wir mit JavaScript nachbauen, indem wir alle h2- und h3-Überschriften auslesen und eine entsprechende Navigation erstellen.[5][6]


Einhängen des Inhaltsverzeichnisses

Seiten mit mehreren Überschriften sollen nun ein Inhaltsverzeichnis erhalten. Dies soll aber nicht vom Anwender bereits im HTML-Markup vorgesehen, sondern dynamisch eingefügt werden:

Einhängen des ToC ansehen …
function generateToC() {
	document.querySelector('h1').insertAdjacentHTML('afterend', `
		<nav aria-labelledby="sections-heading" aria-label="Table of Contents">
			<h6 id="sections-heading">Inhaltsverzeichnis</h6>
			<ul>
			</ul>
		</nav>
	`);
}

Unser Inhaltsverzeichnis besteht aus einer (noch) leeren ul-Liste, die von einem nav-Element umschlossen wird. Über ein aria-labelledby-Attribut wird der Zusammenhang zur h6-Überschrift hergestellt. Das Ganze wird mit insertAdjacentHTML nach der (hoffentlich) nur einmal im Dokument vorkommenden h1-Überschrift eingehängt.

Erzeugen der Links und der Seitenanker

Mit querySelectorAll('h2, h3, h4') werden alle Überschriften der zweiten, dritten und vierten Kategorie selektiert und in einer live node list gespeichert. Dann werden die benötigten Informationen extrahiert:

  • Der Text innerhalb der Tags
  • Die Hierarchietiefe (h2 oder h3)
  • die Element-id, auf die verlinkt werden soll. Falls keine id existiert, muss eine angelegt werden!
Auslesen der Überschriften ansehen …
function generateToC() {
  ...
// alle Überschriften sammeln
  document.querySelectorAll('h2, h3, h4, h5').forEach(heading => {
		const
			ul = document.querySelector('[aria-labelledby="sections-heading"] ul'),
			li = ul.appendChild(document.createElement('li')),
			a = li.appendChild(document.createElement('a'));

		// erzeuge eine ID falls keine vorhanden
		if (!heading.hasAttribute('id')) {
			// verwende Textinhalt der Überschrift in Kleinbuchstaben
			heading.id = heading.textContent.toLowerCase();
		}

		a.href = '#' + heading.id;
		a.appendChild(document.createTextNode(heading.textContent));

		// Ebene für Einrückungen
		if (heading.tagName != 'H2') {
			li.classList.add(
				'toc-level-' + (
					parseInt(heading.tagName.replace(/h/i, ''))
					-1
				).toString()
			);
		}
	});

Die gefundenen Ergebnisse sind nun in einer live node list, die mit einer forEach-Schleife jetzt für jeden Treffer

  • mit textContent die Überschrift ausliest und,
  • wenn die id noch keinen Wert hat, dieser den Text in Kleinbuchstaben zuweist.
  • Die Werte in einen Listeneintrag mit insertAdjacentHTML einfügt.

Dann wird ein Link erzeugt:

  • href besteht aus der Raute für den Seitenanker und heading.id
  • Der Linktext wird mit createTextNode aus heading.textContent erzeugt und dann mit appendChild eingehängt.

Zum Schluss werden die tagNames überprüft, und für h3-h5 Klassen zugewiesen, die per CSS Einrückungen erzeugen.

Wie Counter funktionieren

Zähler teilen sich mit Variablen die Eigenschaft, dass sie einen Gültigkeitsbereich haben. Und genau wie bei Variablen können Gültigkeitsbereiche auch geschachtelt werden. Auf Grund der Arbeitsweise von CSS Zählern – und auf Grund von Merkwürdigkeiten in der Spezifikation – ist dies nicht mit wenigen Worten erklärt.

Erzeugen eines geschachtelten Gültigkeitsbereichs

Bitte betrachte das nachfolgende Beispiel:

Obstsalat
ul {
   counter-reset: obst 0;
}
li {
   counter-increment: obst 1;
}
li::before, p::before {
   content: '(' counter(obst) ') ';
}
<ul id="fruit">
  <li>Bananen</li>
  <li>Äpfel
    <ul id="apples">
       <li>Cox Orange</li>
       <li>Boskop</li>
    </ul>
  </li>
  <li>Birnen
    <ul id="pears">
       <li>Forelle</li>
       <li>Williams Christ</li>
    </ul>
    <p>Glühbirnen</p>
    <ul id="pears2">
       <li>Conference</li>
       <li>Abate Fetel</li>
    </ul>
  </li>
</ul>

Die CSS-Regeln besagen, dass auf <ul>-Elementen ein Zähler namens obst erstellt und auf 0 gesetzt werden soll. Wir haben auch gelernt, dass ein Zähler für das Element, seine Kindelemente und seine nachfolgenden Geschwisterelemente sichtbar ist.

Im gezeigten Beispiel führt das zu mehreren Kollisionen. Zunächst wird auf dem <ul>-Element mit id="fruit" ein obst-Zähler definiert. Dieser gilt im gesamten Bereich des Beispiels. Das <li>-Element „Bananen“ inkrementiert ihn, das <li>-Element „Äpfel“ ebenso. Deswegen findet man vor „Bananen“ eine 1 und vor „Äpfel“ eine 2

Aber was ist nun mit dem <ul>-Element mit id="apples"? Auch hierfür gilt die CSS-Regel mit dem ul-Selektor, so dass erneut angefordert wird, einen Zähler namens obst zu erstellen. Dies geschieht auch, und dieser Zähler verdeckt den obst-Zähler vom fruit-Element. Es gibt nun zwei Zähler, die obst heißen, aber nur der, der zum apples-Element gehört, ist sichtbar. Die <li>-Elemente „Cox Orange“ und „Boskop“ erhöhen nur den sichtbaren Zähler. Deswegen finden sich vor diesem Apfelsorten wieder die Zählerwerte 1 und 2.

Nachdem die Liste mit Apfelsorten und das <li>-Element für Äpfel abgeschlossen sind, ist der Gültigkeitsbereich des neuen obst-Zählers zu Ende. Deswegen wird für das <li>-Element „Birnen“ wieder der obst-Zähler der fruit-Liste verwendet und vor den Birnen erscheint die Nummer 3. Für die Birnenliste gilt das Gleiche wie für die Äpfelliste, vor den Birnensorten stehen die Nummern 1 und 2.

Welchen Zählerwert haben nun die Glühbirnen? Die Birnenliste ist zu Ende, man könnte also meinen, dass wieder der obst-Zähler der fruit-Liste sichtbar ist. Dieser hätte den Wert 3, wir finden vor den Glühbirnen aber eine 2! Die Lösung lautet, dass dies der Zähler aus der pears-Liste ist, denn wie schon erwähnt, gilt ein Zähler für die Kindelemente und die nachfolgenden Geschwisterelemente desjenigen Elements, auf dem er definiert wurde.

Damit ist das Thema aber noch nicht fertig besprochen. Nach den Glühbirnen folgt eine weitere Birnenliste pears2. Auch diese Liste definiert einen neuen obst-Zähler, und vor Conference und Abate Fetel findet man dementsprechend die 1 und die 2. Aber wieviele Zähler haben wir an dieser Stelle nun? Vorhin schrieben wir, dass ein neuer, gleichnamiger Zähler einen vorhandenen Zähler überlagert. Demnach müsste es innerhalb der pears2-Liste also drei obst-Zähler geben. Andererseits wäre das unlogisch, denn die beiden Birnenlisten stehen ja nebeneinander.

Diese Frage klärt sich, wenn wir uns mit einer anderen Frage beschäftigen:

Wie gebe ich den Wert eines verdeckten Zählers aus – counters()

Wozu sollte das gut sein? Nun, für sich alleine ist ein verdeckter Zähler nicht unbedingt nützlich, aber wenn man eine geschachtelte Liste hat, möchte man vielleicht die Hierarchie der Nummerierungen ausgeben. Also vor den Cox Orange nicht einfach eine 1, sondern die 2.1, als erster Unterpunkt des zweiten Eintrags der Früchteliste. CSS bietet hierfür die Funktion counters() an.

Syntax

counters(zählername, zwischenzeichen, list-style-type)

Die counters()-Funktion benötigt im Vergleich zu counter() einen weiteren Parameter: das Zeichen (oder die Zeichenkette), die zwischen die Werte zweier Zählerinstanzen zu setzen ist. Der Stiltyp ist weiterhin optional und steht deswegen am Ende der Parameterliste. Wenn für den angegebenen Zählernamen nur ein Zähler erzeugt wurde, ist das Ergebnis von counters() identisch mit counter(). Gibt es aber mehrere, so werden alle Zähler dieses Namens, beginnend mit dem zuerst erzeugten, gemäß dem gewünschten Listenstil aufbereitet und zu einer langen Zeichenkette zusammengefügt. Zwischen den Zählerwerten wird jeweils das angegebene Zwischenzweichen eingefügt.

Verändern wir an unserem Obstsalatbeispiel eine Kleinigkeit und schauen uns an, was das bewirkt:

Hierarchisch nummerierter Obstsalat ansehen …
li::before, p::before {
   content: '(' counters(obst, '.') ') ';
}

Das Beispiel zeigt eine zweistufige Nummerierung bei den Äpfeln und beiden Birnenlisten.

Auch bei den Glühbirnen ist die counters()-Ausgabe zweistufig. Für sie gilt, wie beschrieben, noch der geschachtelte Zähler der ersten Birnenliste.

Und warum ist die zweite Birnenliste nicht dreistufig? CSS unterscheidet, ob ein Zähler von einem Eltern- oder Geschwisterelement geerbt wird. Das weiß es, weil ein Zähler immer dem Element zugeordnet ist, auf dem er erstellt wurde. Ein von Geschwistern geerbter Zähler wird ersetzt. Ein von Eltern geerbter Zähler wird hingegen überlagert.

Beachte: Eine Mischung von Listenstilen ist bei einer counters()-Aufbereitung nicht möglich. Auf jeder Zählerstufe wird der gleiche Stil angewendet.

Überschriften mit geschachtelten Zählern

Zu Beginn des Artikels hatten wir eine Überschriftennummerierung vorgestellt, die mit unterschiedlichen Zählern je Überschriftenstufe arbeitet. Geht das auch mit geschachtelten Zählern?

Die Antwort lautet Im Prinzip schon, aber.... Damit counter-reset einen Zähler neu anlegt und einen gleichnamigen Zähler überlagert, muss dieser von einem Elternelement übernommen werden. Das bedeutet, dass Ihr HTML-Dokument exakt so aufgebaut sein muss, dass sich die inhaltliche Schachtelung als Elementschachtelung wiederfindet. Dazu kann man das <section>-Element verwenden:

Dokumentstruktur mit Sections
<main>
  <section>
    <h1>Kapitel</h1>
    <p>Einleitung...</p>
    <section>
      <h2>Unterkapitel</h2>
      <p>Text Text...</p>
      <section>
        <h3>Unterunterkapitel</h3>
        ...
      </section>
      <section>
        <h3>Unterunterkapitel</h3>
        ...
      </section>
    </section>
    <section>
        <h2>Unterkapitel</h2>
      ...
    </section>
  </section>
  <section>
    <h1>Kapitel</h1>
    ...
  </section>
</main>

Ausgehend von dieser Struktur kann man entweder auf section-Elementen oder den Überschriften h1 bis h6 einen Überschriftenzähler definieren.

Zählerdefinition für die Dokumentstruktur mit Sections
section:first-of-type { 
  counter-reset: abschnitt 0;
}
:is(h1,h2,h3,h4,h5,h6)::before {
  counter-increment: abschnitt;
  content: counters(abschnitt, '.');
}

Die erste Sub-Sektion einer Sektion erzeugt einen neuen, geschachtelten Zähler. Dieser gilt dann bis zum Ende der Sektion und wird bei jeder Überschrift hochgezählt.

Dieses Verfahren ist möglich, es ist aber nicht zu empfehlen, eine solche Struktur von Hand zu erstellen und intakt zu halten. Die Wahrscheinlichkeit, dass bei Umstrukturierungen des Texts die Struktur nicht sauber gepflegt wird, ist zu hoch. HTML ist keine Textverarbeitung.

+++ ab hier noch zu überarbeiten +++

Erzeugen einer verschachtelten Zählhierarchie ansehen …
ol {
    counter-reset: table-of-content;
    list-style-type: none;
}
li::before {
    counter-increment: table-of-content;
    content: counters(table-of-content,".", decimal) " ";
	color: red;
	font-weight: bold;
}

Das CSS zählt verschachtelte Listenelemente als "1", "1.1", "1.1.1", usw.

Die counters()-Funktion benötigt einige Zeilen weniger, kann aber nicht für die Zählung verschiedener Elemente, bzw. für unterschiedliche Formatierungen verwendet werden.

Beachte: counters() funktioniert nur dann richtig, wenn Ihr Listen-Markup gültig ist. Eine geschachtelte Liste ist immer auch ein Listenelement, muss also in <li>...</li> eingeschlossen sein. Wenn du das vergisst, werden die li-Elemente hinter der geschachtelten Liste falsch nummeriert. An diesem Problem wird zwar auch seitens der Spezifikationsautoren und Browserhersteller gearbeitet, aber das hat zu Unfug in der Lists and Counters-Spezifikation geführt und nur Firefox hat bisher versucht, daraus eine sinnvolle Implementierung zu machen.


Die Zählerliste und Wertevererbung

Jedes Element im DOM besitzt eine Zählerliste (counter set). Sie wird zunächst durch Vererbung gefüllt, und zwar

  • aus den Zählern in der Zählerliste seines Elternelements
  • aus den Zählern in der Zählerliste seines vorhergehenen Geschwisterelements.

Existiert auf Elternelement und vorhergehendem Geschwisterelement ein Zähler mit gleichem Namen, so werden gemäß dem Arbeitsentwurf der Spezifikation vom 09.07.2020 beide Zähler übernommen. Der Zähler aus dem Geschwisterelement überlagert dabei den Zähler des Elternelements. Der nachfolgende Arbeitsentwurf vom 17.11.2020 besagt hingegen, dass der Zähler des Geschwisterelements nur übernommen werden soll, wenn es keinen gleichnamigen Zähler auf dem Elterelement gibt. Diese Änderung wird bisher nur von Firefox realisiert, und auch nur für Listen! Siehe dazu auch den unten stehenden „Beachten“ Einschub und das nachfolgende Kapitel)

CSS hält für jeden Zähler das Element fest, in dem er definiert wurde, so dass auch nach mehrfacher Vererbung eines Zählers immer noch bekannt ist, wo er ursprünglich herkam.

Das gilt aber nur für die Zähler selbst, nicht ihre Werte. Die Werte der so gefundenen Zähler werden aus dem Element übernommen, das dem betrachteten Element in der Baumreihenfolge des DOM vorangeht. Auf diese Weise ist es möglich, auch über tiefer geschachtelte HTML-Strukturen hinweg fortlaufende Zähler zu erzeugen.

ToDo (weitere ToDos)

Bild mit Visualisierung der Vererbung
Beachte: Die Vererbungsregel vom Juli 2020, dass Zähler auf dem vorhergehenden Geschwisterelement Vorrang vor einem gleichnamigen Zähler des Elternelements haben, führt zu Problemen bei falsch geschachtelten Listen. Normalerweise muss eine geschachtelte Liste mit <li>...</li> umgeben werden, aber viele Autoren und auch HTML-Tools tun das nicht. Erstellt man dann mit counters() eine hierarchische Nummerierung, ist sie hinter der geschachtelten Liste falsch. Der Arbeitsentwurf von November 2020 möchte das lösen und, indem Zähler vom Geschwisterelement keine Zählerschachtelung auslösen, wenn sie damit einen Zähler aus dem Elternelement überlagern würden. Das stellt allerdings einen breaking-change für die Semantik von Zählern dar und wurde deshalb in Chrome bisher (Januar 2024) nicht implementiert. Firefox implementiert es, aber nur für Listen.

Erzeugen von Zählern

Nachdem alle vererbten Zähler in die Zählerliste eines Elements eingetragen und mit Werten versehen wurden, werden die CSS-Eigenschaften des Elements selbst verarbeitet. Diese können neue Zähler anlegen und die Werte bestehender Zähler verändern.

Die Eigenschaften counter-increment und counter-set erzeugen nur dann einen neuen Zähler, wenn noch kein Zähler mit dem verwendeten Namen existiert. Andernfalls modifizieren sie den vorhandenen Zähler - bei einem Stapel gleichnamiger Zähler den, der „oben“ auf dem Stapel liegt.

Das Abrufen eines bisher undefinerten Zählers mit counter() oder counters() erzeugt ebenfalls einen neuen Zähler mit diesem Namen.

Die counter-reset-Eigenschaft erzeugt auf jeden Fall einen neuen Zähler und weist ihm einen Wert zu. Falls ein gleichnamiger Zähler bereits existiert und vom Elternelement geerbt wurde, wird ein neuer Zähler mit gleichem Namen angelegt, der den geerbten Zähler überlagert. Auf diese Weise kann ein Stapel aus Zählern gleichen Namens entstehen. Ein Zähler, der von einem Geschwisterelement geerbt wurde, wird hingegen ersetzt.

Auf diese Weise werden Zähler für geschachtelte Listen realisiert, counter-increment, counter-set und counter() greifen immer auf die Zählerinstanz zu, die zum nächstgelegenen Elternelement gehört. Die counters() Funktion sammelt hingegen die Werte aller Zählerinstanzen dieses Namens ein, womit sich hierarchische Nummerierungen erzeugen lassen.

Manipulieren von Zählern

Außer einer einfachen Inkrementierung unterstützt counter-increment auch eine explizite Angabe des Wertes, der auf den Zählerstand aufaddiert werden soll. Wenn man einen reversed()-Counter verwendet, muss explizit den Wert -1 verwendet werden. reversed-Counter sind zwar zum Abwärtszählen gedacht, aber der Defaultwert von counter-increment stört sich daran nicht.

Zählen in Zweierschritten
p {
   counter-increment: absatz 2;
}

Die Eigenschaft counter-reset legt den rückgesetzten Zähler grundsätzlich neu an. Wenn man lediglich den Wert eines geerbten Zählers auf einen neuen Wert setzen will, ist counter-reset deshalb nicht brauchbar. Hierfür gibt es die counter-set Eigenschaft, mit der ein geerbter Zähler auf einen neuen Wert gesetzt werden kann.

Reversed Zähler

Ein reversed() Zähler kann mit counter-reset erzeugt werden und verhält sich im Prinzip wie ein normaler Zähler. Selbst der Standardwert für counter-increment ist immer noch +1. Die Besonderheit eines solchen Zählers ist, dass man ihm keinen Anfangswert zuweisen muss. Man kann es natürlich, wenn man möchte, aber dann hat reversed() keine zusätzliche Funktion.

Wenn der Browser einen reversed()-Zähler ohne Initialwert erzeugt, analysiert er während der Erstellung des Seitenlayout den Geltungsbereich dieses Zählers, und zwar in Baumreihenfolge des DOM. Dieser Geltungsbereich besteht aus den Kindelementen des Elements, auf dem der Zähler erzeugt wird, sowie aus seinen nachfolgenden Geschwisterelementen und deren Kindern (also all die Elemente, die diesen Zähler als Wertequelle nutzen können). Der Geltungsbereich wird dort unterbrochen, wo mittels counter-reset ein anderer Zähler dieses Namens erzeugt wird.

Der Browser beginnt nun mit einem Startwert von 0. Findet er in im Geltungsbereich counter-increment Angaben für diesen Zähler, zieht er ihren Inkrementwert vom Startwert ab. Der erste Inkrementwert wird dabei doppelt gerechnet, das ist erforderlich, damit das Ergebnis am Ende passt. Falls er im Geltungsbereich eine counter-set-Angabe findet, addiert er den set-Wert zum Startwert und bricht den Durchlauf ab.

Der reversed() Zähler wird dann auf den so gefundenen Startwert initialisiert. Auf diese Weise wird erreicht, dass ein reversed()-Zähler, in dessen Geltungsbereich ein counter-set steht, exakt an diesem Wert ankommt. Ohne counter-set entsteht der Effekt, dass der Zähler bei 1 endet. Probier es aus!

Achtung!

Bei großen Dokumenten kann diese Analyse die Layoutphase des Browsers verzögern. Nutze reversed()-Zähler vorsichtig beziehungsweise miss die Performance ihrer Seite.

Siehe auch

  • Bildergalerie mit Grid Layout, deren Kindelemente sich an den verfügbaren Platz anpassen. Zur besseren Kennzeichnung der Reihenfolge im Markup wurden sie mit counter() nummeriert.

Weblinks

  1. W3C, Automatische Zähler und Nummerierung
  2. MDN: CSS Zähler verwenden
  3. Dieser Artikel ist die umfassende Neubearbeitung eines Selfhtml-aktuell-Artikels von Thomas J. Sebestyen aus dem Jahre 2002 mit dem Thema Listen automatisch mit hybrider Nummerierung formatieren. Damals musste über Klassen selektiert werden, da der IE keine Nachfahrenselektoren wie ol ol kannte.
    --Matthias Scharwies (Diskussion) 08:10, 25. Okt. 2020 (CET)
  4. Hilfe:Wiki/Inhaltsverzeichnis
    Gliederung und Darstellung des Inhaltsverzeichnisses im SELFHTML-Wiki
  5. css-tricks: Parsing Markdown into an Automated Table of Contents von Lisi Linhart am 13.11.2020
  6. A Perfect Table of Contents With HTML + CSS von Nicholas C. Zakas on May 25, 2022 (css-tricks.com)