Zum Inhalt springen

Selektoren im Detail

Für den Browser ist ein HTML-Dokument kein Text, sondern ein Baum aus verschachtelten Elementen: das Document Object Model (DOM). Selektoren wählen Knoten in genau diesem Baum aus.

Dafür ein paar Fachbegriffe, die in CSS-Doku und Fehlermeldungen immer wieder auftauchen:

  • Element / Node - ein einzelner Knoten im Baum (ein Tag oder ein Text)
  • Eltern-Element - der Knoten eine Ebene darüber
  • Kinder - die Knoten eine Ebene darunter
  • Vorfahren - alle Knoten darüber, beliebig viele Ebenen
  • Nachkommen - alle Knoten darunter, beliebig viele Ebenen

Der Stern * wählt alle Elemente im Dokument aus:

* {
box-sizing: border-box;
}

Das kennt ihr schon aus dem Box-Modell-Abschnitt. Genau darum wird der Universal-Selektor in der Praxis fast nur für diesen einen Reset verwendet, nicht für echtes Styling. Zu allgemeine Regeln treffen zu viel und sind schwer vorhersehbar.

Eine id muss im Dokument einzigartig sein. Deshalb ist sie nicht nur für CSS nützlich, sondern auch als Textmarke in der URL aufrufbar:

<body>
<nav id="menu">Navigation...</nav>
<footer id="copyright">© ...</footer>
</body>

Angenommen, diese Seite ist unter https://example.com/seite.html erreichbar. Dann springt der Browser bei folgenden URLs direkt zur jeweiligen Stelle:

  • https://example.com/seite.html#menu
  • https://example.com/seite.html#copyright

Der CSS-Selektor verwendet dieselbe Raute (#):

#menu { background-color: yellow; }

Nachfahren nochmal genauer: der Descendant Combinator

Abschnitt betitelt „Nachfahren nochmal genauer: der Descendant Combinator“

Ein Leerzeichen zwischen zwei Selektoren wählt alle Elemente aus, die irgendwo verschachtelt in einem anderen Element liegen. Egal wie tief:

<section>
<a href="#">direkter Link</a>
<p>Text mit <a href="#">verschachteltem Link</a></p>
</section>
section a {
color: darkorange;
}

Beide a-Tags werden getroffen, auch der, der zwei Ebenen tief in einem p steckt.

Browser unterscheiden bei <a>-Tags automatisch zwischen mehreren Zuständen - dafür gibt es eigene Pseudo-Klassen:

a:link { color: blue; } /* noch nicht besucht */
a:visited { color: purple; } /* schon einmal besucht */
a:hover { color: red; } /* Maus ist gerade drüber */
a:active { color: orange; } /* wird gerade angeklickt */
Pseudo-KlasseWann aktiv?
:linkLink wurde noch nicht besucht
:visitedLink wurde schon einmal besucht
:hoverMaus befindet sich über dem Element (auf Touch-Geräten wirkungslos)
:activeElement wird gerade geklickt/getippt - nur für einen kurzen Moment

Neben :hover gibt es :focus - aktiv, wenn ein Element per Tastatur (Tab-Taste) oder Klick den Eingabefokus hat:

button:focus,
a:focus {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
  • Nicht nur Links/Buttons können fokussiert werden - auch Formularfelder (input, textarea, select)
  • Der Browser zeigt standardmäßig einen outline-Rahmen bei Fokus - das ist für Tastatur-Nutzer*innen die einzige visuelle Rückmeldung, welches Element gerade “aktiv” ist

Der Descendant Combinator (Leerzeichen) trifft beliebig tief verschachtelte Nachkommen. Der Child Combinator > ist strenger. Er trifft nur direkte Kinder:

<ul class="menu">
<li><a href="#">direktes Kind</a></li>
<li><span><a href="#">zwei Ebenen tief</a></span></li>
</ul>
.menu > a { color: yellow; } /* trifft KEIN a - die a-Tags sind Enkel, nicht Kinder */
li > a { color: yellow; } /* trifft nur das erste a, direktes Kind von li */

Document Object Model und Selektor

Elemente lassen sich auch anhand ihrer HTML-Attribute auswählen. Zum Beispiel alle Links, deren href mit mailto: beginnt:

a[href^="mailto:"] { color: yellow; }

Document Object Model und Selektor

Es gibt mehrere Varianten:

a[href] /* Attribut existiert, egal mit welchem Wert */
a[href="https://example.com"] /* Attribut hat genau diesen Wert */
a[href^="mailto:"] /* Wert beginnt mit ... */
a[href$=".pdf"] /* Wert endet mit ... */
a[href*="example"] /* Wert enthält ... irgendwo */

Geschwister zählen: :first-child, :last-child, :nth-child()

Abschnitt betitelt „Geschwister zählen: :first-child, :last-child, :nth-child()“

Diese Pseudo-Klassen wählen ein Element anhand seiner Position unter Geschwister-Elementen aus, unabhängig vom Tag-Namen:

li:first-child { font-weight: bold; } /* nur das erste li in seiner Liste */
li:last-child { border-bottom: none; } /* nur das letzte li */
li:nth-child(odd) { background-color: #f9fafb; } /* 1., 3., 5., ... */
li:nth-child(even) { background-color: white; } /* 2., 4., 6., ... */
li:nth-child(3) { color: red; } /* genau das dritte */

Document Object Model und Selektor

Manche Selektoren wählen keinen ganzen DOM-Knoten aus, sondern nur einen Teil davon. Erkennbar sind sie am doppelten Doppelpunkt :::

p::first-letter { font-size: 2em; } /* nur der erste Buchstabe */
p::first-line { font-weight: bold; } /* nur die erste (gerenderte) Zeile */
::selection { background-color: gold; } /* der aktuell markierte Text */

Document Object Model und Selektor

section a wählt ein a innerhalb einer section. Manchmal will man aber das Elternelement selbst auswählen, abhängig davon, was es enthält. Dafür gibt es :has():

/* section, falls sie MINDESTENS EINEN Link enthält */
section:has(a) {
border-left: 3px solid gold;
}

Document Object Model und has pseudo class

Praxisbeispiel: Ein Formularfeld rot markieren, wenn eine leere Option ausgewählt ist:

select:has(option[value=""]:checked) {
border-color: red;
}
<select>
<option value="">--- Bitte wählen ---</option>
<option value="fluss">Fluss</option>
<option value="see">See</option>
</select>

Kombinierte Selektoren: das Komma hat die geringste Präzedenz

Abschnitt betitelt „Kombinierte Selektoren: das Komma hat die geringste Präzedenz“
p, section a { color: yellow; }

Dieser Selektor bedeutet: entweder ein p-Element, oder ein a innerhalb einer section. Nicht: “ein Link, der entweder in einem p oder in einer section liegt”.

Document Object Model und Selektor

NameMusterBeschreibung
Universal-Selektor*Trifft jedes Element
Type-SelektorETrifft jedes E-Element
GruppierungE, F, GTrifft E- oder F- oder G-Elemente
Descendant CombinatorE FTrifft jedes F, das Nachkomme eines E ist
Child CombinatorE > FTrifft jedes F, das direktes Kind eines E ist
Klassen-SelektorE.klasseTrifft jedes E mit class="klasse"
ID-SelektorE#idTrifft das E mit id="id"
Link-Pseudo-Klassen:link :visitedNoch nicht besuchter / bereits besuchter Link
Dynamische Pseudo-Klassen:hover :active :focusTrifft während bestimmter Interaktionen (Maus drüber, wird geklickt, hat Fokus)
Attribut-SelektorE[attr^="wert"]Trifft, wenn ein Attributwert mit wert beginnt (auch $=, *=, =)
:has()-Pseudo-KlasseE:has(F)Trifft jedes E, das ein F als Nachkomme enthält
:target-Pseudo-Klasse:targetTrifft das Element, dessen ID mit dem #anker in der URL übereinstimmt
:root-Pseudo-Klasse:rootTrifft die Wurzel des DOM, immer <html>
:nth-child() u.ä.:first-child :nth-child(3) :nth-child(odd) :last-childZählt Geschwister-Elemente, trifft je nach Position
Pseudo-ElementeE::first-letter E::first-line ::selectionWählt nur einen Teil eines Elements, keinen eigenen DOM-Knoten