Generierte Inhalte, attr()-Werte, Zaehler und Icons ohne zusaetzliches HTML
content bei ::before und ::after wird oft nur fuer leere dekorative Elemente genutzt, kann aber deutlich mehr: attr() liest HTML-Attribute direkt aus, counter() nummeriert Listen und Kapitel automatisch, und content: url() bindet Bild-Icons ein, ganz ohne zusaetzliches Markup. Wer diese Moeglichkeiten kennt, spart HTML-Elemente, muss dabei aber die Zugaenglichkeits-Grenzen von generiertem Inhalt genau verstehen.
Inhaltsverzeichnis
- 1. content bei ::before und ::after: mehr als nur reiner Text
- 2. content mit reinem Text: Quotes, Escaping und typische Einsatzzwecke
- 3. attr(): HTML-Attribute direkt in generierten Inhalt einfuegen
- 4. counter(): automatische Nummerierung fuer Listen und Kapitel
- 5. Icon-Fonts gegen content-generierte SVG- und Unicode-Icons
- 6. content: url() fuer Bild-Icons ohne zusaetzliches img-Element
- 7. Zugaenglichkeits-Implikationen: was Screenreader mit generiertem Inhalt tun
- 8. Praktisches Rezept: Tooltip-Pfeile und Zaehler-Badges mit content
- 9. Wann content nicht die richtige Wahl ist
- 10. Zusammenfassung
- 11. FAQ
1. content bei ::before und ::after: mehr als nur reiner Text
Die content-Eigenschaft ist zwingend erforderlich, damit ein ::before- oder ::after-Pseudo-Element ueberhaupt sichtbar wird, selbst ein leerer String content: "" reicht dafuer aus. In der Praxis wird content aber meist nur fuer feste Text-Strings oder leere dekorative Elemente eingesetzt, obwohl die Spezifikation deutlich mehr Datentypen erlaubt: HTML-Attribute, automatische Zaehler und sogar externe Bild-Ressourcen.
Der entscheidende Unterschied zu echtem HTML-Inhalt ist, dass generierter Inhalt niemals Teil des DOM wird. Er erscheint visuell und wird in bestimmten Faellen von Screenreadern vorgelesen, laesst sich aber nicht mit JavaScript selektieren, nicht kopieren und nicht ueber document.querySelector ansprechen. Diese Eigenschaft macht content ideal fuer rein praesentationelle Ergaenzungen, aber ungeeignet fuer inhaltlich relevante Informationen.
2. content mit reinem Text: Quotes, Escaping und typische Einsatzzwecke
Der einfachste Fall ist ein fester String in Anfuehrungszeichen, etwa fuer typografische Anfuehrungszeichen bei Zitaten, Trennzeichen zwischen Breadcrumb-Elementen oder ein Sternchen bei Pflichtfeldern in Formularen. Sonderzeichen lassen sich entweder direkt als Unicode-Zeichen im CSS einfuegen oder ueber Escape-Sequenzen wie \2192 fuer einen Pfeil nach rechts, was bei Encoding-Problemen im Editor die robustere Variante ist.
Wichtig ist, dass reiner Text-Content bei jedem Rendering neu erzeugt wird und nicht Teil der eigentlichen Seitensprache im Sinne von uebersetzbaren Strings ist. Fuer mehrsprachige Websites sollte deshalb kein inhaltlich bedeutsamer Text ueber content eingefuegt werden, sondern nur rein dekorative oder sprachneutrale Symbole wie Trennzeichen oder Pfeile.
.breadcrumb li:not(:last-child)::after {
content: " \2192 "; /* Pfeil nach rechts als Trenner */
color: #94a3b8;
}
.pflichtfeld label::after {
content: " *";
color: #dc2626;
}
3. attr(): HTML-Attribute direkt in generierten Inhalt einfuegen
Die Funktion attr() liest den Wert eines HTML-Attributs des aktuellen Elements aus und fuegt ihn als Text in content ein. Ein haeufiger Einsatz ist die Anzeige von data-Attributen, etwa ein Tooltip-Text aus data-tooltip, ohne dass dafuer ein zusaetzliches HTML-Element noetig waere, das den Text dupliziert.
Der grosse Vorteil gegenueber dupliziertem Markup ist, dass sich Aenderungen am data-Attribut per JavaScript sofort auf den sichtbaren Inhalt auswirken, ganz ohne dass CSS oder der generierte Inhalt selbst angefasst werden muessen. Die Grenze von attr() ist, dass es aktuell nur Strings liefert, keine strukturierten Werte, und dass es sich nicht fuer sicherheitskritische oder rein inhaltliche Informationen eignet, weil Screenreader-Unterstuetzung fuer attr()-Werte inkonsistent ist.
<span class="tooltip-trigger" data-tooltip="Kostenloser Versand ab 50 Euro">
Versandkosten
</span>
<style>
.tooltip-trigger::after {
content: attr(data-tooltip);
display: none;
position: absolute;
background: #1e293b;
color: white;
padding: 0.5rem;
border-radius: 0.375rem;
}
.tooltip-trigger:hover::after {
display: block;
}
</style>
4. counter(): automatische Nummerierung fuer Listen und Kapitel
CSS-Zaehler mit counter-reset, counter-increment und der counter()-Funktion innerhalb von content erzeugen automatische Nummerierungen, die bei jeder Aenderung der Reihenfolge oder Anzahl der Elemente korrekt bleiben, ohne dass eine einzige Zahl manuell im HTML gepflegt werden muss. Das ist besonders nuetzlich bei verschachtelten Strukturen wie mehrstufigen FAQ-Listen oder Tutorial-Kapiteln.
Verschachtelte Zaehler koennen sogar mehrstufige Nummerierungen wie 2.3 erzeugen, indem ein aeusserer und ein innerer Zaehler kombiniert werden. Der Browser verwaltet dabei automatisch die Verschachtelungstiefe, solange counter-reset auf dem umschliessenden Element und counter-increment auf jedem gezaehlten Kindelement korrekt gesetzt sind.
.kapitel-liste {
counter-reset: kapitel;
}
.kapitel-liste .kapitel {
counter-increment: kapitel;
}
.kapitel-liste .kapitel::before {
content: "Kapitel " counter(kapitel) ": ";
font-weight: bold;
}
5. Icon-Fonts gegen content-generierte SVG- und Unicode-Icons
Icon-Fonts binden Icons als Zeichen einer speziellen Schriftart ein und nutzen dafuer haeufig content mit einem Unicode-Codepunkt, der in der Icon-Schriftart auf ein Glyphen-Symbol statt eines Buchstabens zeigt. Das funktioniert visuell zuverlaessig, hat aber einen strukturellen Nachteil: Screenreader lesen den zugrunde liegenden Unicode-Codepunkt oft als bedeutungslosen Buchstaben oder gar nicht vor, was ohne zusaetzliche aria-hidden-Behandlung verwirrende Ausgaben erzeugt.
Als moderne Alternative bindet content: url("icon.svg") eine echte SVG-Datei als generierten Inhalt ein, ohne die Font-Datei-Abhaengigkeit und ohne das Risiko fehlerhafter Zeichenkodierung. Der Nachteil gegenueber Icon-Fonts ist, dass sich SVG-Icons ueber content: url() nicht per CSS einfaerben lassen, waehrend Icon-Font-Zeichen einfach mit color gefaerbt werden koennen, weil sie technisch Text sind.
/* Icon-Font-Ansatz: einfaerbbar, aber Codepunkt-Risiko */
.icon-warenkorb::before {
content: "\e901";
font-family: "IconFont";
color: #4a1d96; /* faerbbar */
}
/* SVG-Ansatz: robuster, aber nicht einfaerbbar per CSS */
.icon-warenkorb-svg::before {
content: url("/icons/warenkorb.svg");
}
6. content: url() fuer Bild-Icons ohne zusaetzliches img-Element
content: url() laedt eine Bilddatei, meist SVG oder PNG, und rendert sie als generierten Inhalt des Pseudo-Elements, ohne dass dafuer ein <img>-Tag im HTML noetig ist. Das ist praktisch fuer rein dekorative Icons, die konsequent nur ueber CSS gesteuert werden sollen, etwa ein Haekchen-Symbol vor jedem Listenpunkt einer Feature-Liste.
Wichtig ist, dass ueber content: url() geladene Bilder in ihrer Originalgroesse gerendert werden und sich nicht mit width oder height auf dem Pseudo-Element skalieren lassen. Fuer skalierbare Icon-Groessen ist deshalb entweder ein SVG mit passend gesetzter Original-Groesse noetig, oder ein Wechsel zu background-image mit background-size, das echte Groessenkontrolle bietet.
.feature-liste li::before {
content: url("/icons/check-16.svg"); /* feste 16px-Groesse im SVG selbst */
margin-right: 0.5rem;
vertical-align: middle;
}
7. Zugaenglichkeits-Implikationen: was Screenreader mit generiertem Inhalt tun
Das Verhalten von Screenreadern gegenueber content-generiertem Text ist uneinheitlich zwischen Browsern und Assistenztechnologien: Manche lesen reinen Text-Content vor, andere ignorieren ihn komplett, wieder andere lesen ihn nur unter bestimmten Konfigurationen. Diese Unsicherheit bedeutet in der Praxis: content darf niemals die einzige Quelle fuer inhaltlich wichtige Information sein, etwa eine Fehlermeldung oder ein Pflichtfeld-Hinweis, der ausschliesslich per CSS eingeblendet wird.
Fuer rein dekorative generierte Inhalte, etwa Trennzeichen, Icon-Symbole oder visuelle Zaehler-Nummern, die keine eigene Bedeutung tragen, ist das inkonsistente Vorlesen unproblematisch, weil ohnehin niemand erwartet, dass sie vorgelesen werden. Kritisch wird es nur, wenn ein Entwickler versehentlich echten Inhalt in content auslagert, der dann fuer Screenreader-Nutzer teilweise unsichtbar wird, obwohl er visuell klar erkennbar ist.
8. Praktisches Rezept: Tooltip-Pfeile und Zaehler-Badges mit content
Ein CSS-Tooltip mit sichtbarem Pfeil, der auf das Ausloeser-Element zeigt, laesst sich vollstaendig ueber zwei Pseudo-Elemente bauen: ::before fuer die Tooltip-Box selbst mit content: attr(data-tooltip), und ::after fuer einen kleinen gedrehten Quadrat-Pfeil mit leerem content: "", der nur durch Border-Tricks wie ein Dreieck aussieht.
Ein Warenkorb-Badge mit Artikelanzahl kombiniert counter() oder attr() mit absoluter Positionierung: content: attr(data-count) zeigt die Zahl aus einem data-count-Attribut an, das per JavaScript oder Alpine.js aktualisiert wird, waehrend das Pseudo-Element selbst nur fuer die visuelle Kreisform und Positionierung zustaendig ist.
<button class="warenkorb-icon" data-count="3">
Warenkorb
</button>
<style>
.warenkorb-icon {
position: relative;
}
.warenkorb-icon::after {
content: attr(data-count);
position: absolute;
top: -6px;
right: -6px;
background: #dc2626;
color: white;
border-radius: 9999px;
font-size: 0.7rem;
padding: 0.1rem 0.4rem;
}
</style>
9. Wann content nicht die richtige Wahl ist
Jeder Inhalt, der fuer das Verstaendnis der Seite notwendig ist, gehoert ins eigentliche HTML-Markup, nicht in generierten CSS-Inhalt. Das gilt fuer Produktnamen, Preise, Fehlermeldungen, Formularhinweise und alles, was ein Nutzer kopieren, per Suchfunktion im Browser finden oder von einem Screenreader zuverlaessig vorgelesen bekommen soll. Generierter Inhalt ist ein Werkzeug fuer Praesentation, nicht fuer Semantik.
| Methode | Einfaerbbar per CSS | Skalierbar | Screenreader-Verhalten |
|---|---|---|---|
| Icon-Font (content + Codepunkt) | Ja, ueber color | Ja, ueber font-size | Uneinheitlich, oft Codepunkt hoerbar |
| content: url() mit SVG | Nein | Nein, feste Bildgroesse | Meist ignoriert, unproblematisch fuer Deko |
| Inline SVG im HTML | Ja, ueber fill/stroke | Ja, ueber width/height | Kontrollierbar via aria-hidden/title |
| background-image | Nein | Ja, ueber background-size | Immer ignoriert, rein dekorativ |
| attr() fuer Text/Zahlen | Ja, wie normaler Text | Ja, ueber font-size | Uneinheitlich, nicht fuer wichtige Infos geeignet |
Mironsoft
Modernes CSS, Layout-Architektur und Rendering-Performance
CSS, das wartbar bleibt statt mit jeder Änderung zu brechen?
Wir prüfen bestehende Stylesheets auf Spezifitäts-Chaos und Layout-Thrashing und bauen daraus eine CSS-Architektur mit Cascade Layers, Custom Properties und modernen Layout-Primitiven, die auch nach dem zehnten Feature noch verständlich ist.
CSS-Audit
Spezifität, Cascade-Konflikte und ungenutzte Selektoren systematisch aufdecken.
Architektur-Refactoring
Cascade Layers, Custom Properties und Design Tokens sauber einführen.
Performance-Tuning
Layout-Thrashing, teure Selektoren und Rendering-Engpässe gezielt beheben.
10. Zusammenfassung
CSS content-Property: Das Wichtigste auf einen Blick
Grundprinzip
content bei ::before/::after erzeugt rein visuellen, nicht im DOM verankerten Inhalt, ideal fuer Praesentation, nicht Semantik.
attr() und counter()
attr() liest HTML-Attribute direkt aus, counter() erzeugt automatische, immer korrekte Nummerierung ohne manuelle Pflege.
Icons
Icon-Fonts sind einfaerbbar aber mit Screenreader-Risiko, SVG ueber content: url() ist robuster aber nicht per CSS faerbbar.
Zugaenglichkeit
Inhaltlich wichtige Informationen gehoeren immer ins echte HTML, generierter Inhalt bleibt rein dekorativ.