Selektoren und die Kaskade
Kurz gesagt: Ein CSS-Selektor wählt die Elemente aus, für die eine Regel gilt, und die Kaskade entscheidet, welche Regel bei einem Konflikt gewinnt: Herkunft, Spezifität und Reihenfolge.
Problem
Der Preis wird nicht rot
Der Shop startet eine Aktion: Der Preis des Brotes soll rot sein. Ein Kollege fügt ganz unten in style.css eine Regel für .price hinzu. Der Preis wird größer und fett, bleibt aber dunkelgrau.
Konsole
Die Konsole ist leer: CSS meldet keine Fehler. Die Regel ist die letzte in der Datei, und sie trifft den Preis, denn Größe und Fettdruck kommen an. Nur die Farbe nicht. Eine andere Regel will für denselben Absatz eine andere Farbe, und der Browser hat sich für sie entschieden.
Die Idee
Regel und Selektor
CSS sagt, wie jedes Element des Baums aussieht. Es sagt das mit Regeln:
.price { color: #c0392b; font-size: 20px;}.priceist der Selektor: Er bestimmt, auf welche Elemente die Regel zutrifft.- In den geschweiften Klammern stehen die Deklarationen: Eigenschaft, Doppelpunkt, Wert und ein Semikolon.
Selektoren durchsuchen den Baum, sie sind also wie Fragen an ihn:
p(Typ): jedes<p>..price(Klasse): jedes Element mitclass="price". Ein Element kann mehrere Klassen haben:class="price sale".#product(id): das Element mitid="product".[type="email"](Attribut): die Elemente mit diesem Attribut und diesem Wert, zum Beispielinput[type="email"].article p(Nachfahre, mit Leerzeichen): ein<p>irgendwo in einem<article>, in beliebiger Tiefe.nav > a(Kind): ein<a>, das direktes Kind von<nav>ist..price.sale(ohne Leerzeichen): ein Element mit beiden Klassen.h1, h2(Liste): Die Regel gilt für beide.
Stile schreibt man meistens mit Klassen. Ein Typ trifft jeden Absatz der Website, und eine id ist für ein einziges Element. Eine Klasse steht genau dort, wo du sie brauchst, und hängt nicht davon ab, wie der Baum aufgebaut ist.
Probier es aus
Triff genau diese
Nimm die Unterstreichung nur bei den Links im Menü weg (der Link unten bleibt unterstrichen) und mach beide Preise fett, ohne die Beschreibungen fett zu machen. Die Eigenschaften sind text-decoration: none und font-weight: 700.
Konsole
Lösung
index.html<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Der Shop</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<nav>
<a href="/bread">Brot</a>
<a href="/milk">Milch</a>
<a href="/cart">Warenkorb</a>
</nav>
</header>
<main>
<article>
<h2>Dobrudzha-Brot</h2>
<p>Weißbrot, 650 g, heute Morgen gebacken.</p>
<p class="price">1,80 €</p>
</article>
<article>
<h2>Frischmilch 3%</h2>
<p>Ein Liter, von einem Bauernhof bei Teteven.</p>
<p class="price">2,40 €</p>
</article>
</main>
<footer>
<a href="/terms">Lieferbedingungen</a>
</footer>
</body>
</html>
style.cssbody { font-family: system-ui, sans-serif; margin: 16px; }
nav { display: flex; gap: 16px; }
nav a { text-decoration: none; }
.price { font-weight: 700; }
nav a trifft nur die Links in <nav>, während a auch den Link unten treffen würde. .price trifft die zwei Absätze mit der Klasse, während p auch die Beschreibungen fett machen würde. Ohne den Punkt sucht price ein Element <price>, und das gibt es nicht.
Die Idee
Die Kaskade
Den Preis vom Anfang treffen zwei Regeln, und beide setzen color. Der Browser muss eine wählen. Diese Auswahlregel heißt Kaskade. Sie vergleicht auf drei Ebenen und hört bei der ersten auf, die entscheidet:
- Herkunft. Der Browser hat eigene Stile: Deshalb ist
<h1>groß und ein Link blau und unterstrichen. Dein CSS schlägt sie. - Spezifität. Wie genau der Selektor ist. Es sind drei Zahlen: wie viele ids, wie viele Klassen, wie viele Typen.
pist 0,0,1,.priceist 0,1,0,#product pist 1,0,1. Attribute ([type="email"]) und Zustände (:hover) zählen wie Klassen. Die Zahlen werden Spalte für Spalte von links verglichen. Sobald eine Spalte abweicht, ist es entschieden: 1,0,1 schlägt 0,1,0. - Reihenfolge. Bei gleicher Spezifität gewinnt die Regel, die später im Code steht.
Die Kaskade entscheidet jede Eigenschaft einzeln. Deshalb kommen font-size und font-weight von .price an: Nichts anderes konkurriert um sie. Bei color konkurriert etwas, und es ist stärker.
Es gibt auch !important: color: #c0392b !important schlägt jede normale Deklaration, egal welche Spezifität. Es funktioniert, aber danach braucht jede Änderung der Farbe ein neues !important. Es ist also ein Zeichen dafür, dass irgendwo ein Selektor zu stark ist, und keine Lösung.
Sieh es dir an
Sieh zu, wie der Browser wählt
Vier Regeln und ein Element. Achte darauf, wie der Browser color und font-size getrennt entscheidet.
/* <article id="product"> <p class="price sale">1,80 €</p> </article> */p { color: #555; font-size: 16px; }.price { color: #c0392b; font-size: 20px; }#product p { color: #222; }.sale { font-size: 24px; }Schritt für Schritt, in Worten
- Ein Element: ein <p> mit den Klassen price und sale, in <article id="product">. Alle vier Selektoren treffen es. Zwei der Regeln wollen color setzen und drei font-size.
- Die Spezifität eines Selektors besteht aus drei Zahlen: wie viele ids, wie viele Klassen, wie viele Typen. #product p hat eine id und einen Typ: 1,0,1.
- color: Drei Regeln setzen es. Der Browser vergleicht die erste Spalte: 1 schlägt 0, und weiter schaut er nicht. #product p gewinnt, obwohl .price danach kommt.
- font-size: wieder drei Regeln. Die id-Spalte ist gleich (0). In der Klassenspalte fällt p mit 0 heraus. .price und .sale sind in allen drei Spalten gleich.
- Gleiche Spezifität: Die Regel, die später im Code steht, gewinnt. .sale steht in Zeile 7, nach .price, deshalb ist font-size 24px.
- Jede Eigenschaft hat ihren eigenen Gewinner: color von #product p, font-size von .sale. Die Regel .price trifft das Element und verliert trotzdem in beiden.
Hier ist derselbe Code im Browser. Der Preis ist dunkelgrau und 24px groß, wie in der Szene. Tausch .price und .sale: Die Größe ändert sich, die Farbe nicht. Öffne die Entwicklertools (F12), wähl den Preis aus und sieh dir das Panel Stile an: Die unterlegenen Deklarationen sind durchgestrichen.
Konsole
Die Idee
Vererbung
Manche Eigenschaften gehen vom Elternelement auf die Kinder über. Wenn ein Element dafür keine eigene Regel hat, übernimmt es den Wert seines Elternelements. Das ist Vererbung.
- Die Eigenschaften des Textes werden vererbt:
color,font-family,font-size,font-weight,line-height,text-align. - Die Eigenschaften der Box nicht:
border,padding,margin,background,width. Ein Rahmen um die Karte heißt nicht, dass jeder Absatz darin einen Rahmen hat.
Ein geerbter Wert ist der schwächste. Jede Regel, die das Element direkt trifft, schlägt ihn, sogar p mit 0,0,1. Buttons und Felder bekommen ihre eigene Schrift und Farbe vom Browser, deshalb erben sie nicht. inherit verlangt die Vererbung ausdrücklich: button { font-family: inherit; }.
Konsole
Der Text der Karte ist grün und in Georgia, aber der Rahmen ist nur um die Karte. Der Button hat die Schrift wegen inherit übernommen, und seine Farbe blieb schwarz: Für color gibt es keine solche Regel.
Probier es aus
Repariere den Preis
Mach den Preis rot (#c0392b), ohne !important. Die Beschreibung muss dunkelgrau (#222) bleiben.
Konsole
Lösung
index.html<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Dobrudzha-Brot</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<article id="product">
<h1>Dobrudzha-Brot</h1>
<p>Weißbrot, 650 g, heute Morgen gebacken.</p>
<p class="price">1,80 €</p>
<button type="button">In den Warenkorb</button>
</article>
</body>
</html>
style.cssbody { font-family: system-ui, sans-serif; margin: 16px; }
#product { color: #222; line-height: 1.5; }
h1 { font-size: 24px; }
/* Aktion: Der Preis ist rot */
.price { color: #c0392b; font-size: 20px; font-weight: 700; }
Du brauchst keinen stärkeren Selektor für den Preis, sondern einen schwächeren für die Beschreibung. #product { color: #222; line-height: 1.5; } gibt dem Artikel die Farbe, und die Absätze erben sie. Der geerbte Wert verliert gegen .price, das den Preis direkt trifft. #product .price (1,1,0) besteht auch, aber dann braucht die nächste Änderung einen noch stärkeren Selektor. p.price reicht nicht: 0,1,1 verliert in der ersten Spalte weiter gegen 1,0,1.
Probier es aus
Finde den Fehler
Der Preis hat die Klassen price und sale, ist aber nicht rot. Warum?
Wähle die Zeile mit dem Fehler.
Das Leerzeichen in .price .sale heißt „ein Element mit der Klasse sale in einem Element mit der Klasse price“. Hier stehen beide Klassen an einem Element, und dafür schreibt man sie zusammen: .price.sale.
Probier es aus
Ergänze
Das Menü hat Links und eine verschachtelte Liste mit weiteren Links. Nur die Links, die direkte Kinder von <nav> sind, sollen keine Unterstreichung haben.
nav a {
text-decoration: none;
}> trifft nur direkte Kinder. Mit einem Leerzeichen (nav a) würde die Regel auch die Links in der verschachtelten Liste treffen.
Genauer, für Neugierige
Herkunft. Es gibt drei Quellen: den Browser, den Nutzer (Einstellungen und Erweiterungen) und den Autor, also dich. Bei normalen Deklarationen schlägt der Autor den Nutzer, und der Nutzer schlägt den Browser. Mit !important kehrt sich die Reihenfolge um: Das !important des Nutzers schlägt deins. So kann ein Mensch mit schwachen Augen auf jeder Website eine größere Schrift erzwingen.
style="…". Ein Stil im Attribut des Elements schlägt jeden Selektor in der Datei. Er ist also auch eine Falle, wie !important.
Spalten laufen nicht über. 0,11,0 ist nicht 1,1,0. Elf Klassen schlagen eine id nicht: Der Vergleich endet in der ersten Spalte.
Was nicht zählt. * ist 0,0,0. Kombinatoren (Leerzeichen, >, +, ~) fügen nichts hinzu. Pseudoelemente (::before) zählen wie Typen.
:is(), :not() und :where(). :is() und :not() übernehmen die Spezifität ihres stärksten Arguments. :where() ist immer 0,0,0: praktisch für Standardstile, die jede Regel überschreibt.
Ebenen. @layer ordnet ganze Gruppen von Regeln, und die Ebene entscheidet vor der Spezifität. Große Stilbibliotheken nutzen es, damit sie sich nicht mit deinem CSS streiten.
Die Schlüsselwörter. inherit übernimmt den Wert des Elternelements. initial ist der Startwert der Eigenschaft aus dem Standard (bei display ist es inline). unset ist inherit bei vererbten Eigenschaften und initial bei den anderen. revert bringt den Stil des Browsers zurück.
Übung
Die Aktion im Katalog
Der Katalog hat drei Produkte, und die Milch ist im Angebot (die Klasse sale an ihrer Karte). Aller Text im Katalog ist #222, und die Preise sind fett. Der Preis des Produkts im Angebot ist rot (#c0392b), und der alte Preis darin ist grau (#777). Das Label −20% hat weißen Text (#fff) auf rotem Hintergrund (#c0392b). Die anderen Preise bleiben #222. Benutz kein !important.
Konsole
Lösung
index.html<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Katalog</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main id="catalog">
<article class="product">
<h2>Dobrudzha-Brot</h2>
<p class="price">1,80 €</p>
</article>
<article class="product sale">
<h2>Frischmilch 3%</h2>
<p class="badge">−20%</p>
<p class="price"><s class="old">2,40 €</s> 1,92 €</p>
</article>
<article class="product">
<h2>Butter 125 g</h2>
<p class="price">3,20 €</p>
</article>
</main>
</body>
</html>
style.cssbody { font-family: system-ui, sans-serif; margin: 16px; }
#catalog { color: #222; }
.price { font-weight: 700; }
.sale .price { color: #c0392b; }
.old { color: #777; }
.badge { color: #fff; background: #c0392b; }
#catalog p trifft jeden Absatz mit 1,0,1 und schlägt jede Regel aus Klassen. Deshalb kommt die Farbe auf #catalog, und der Text erbt sie. Dann trifft .sale .price (0,2,0) nur den Preis im Angebot, .old gibt dem alten Preis das Grau (sonst würde er das Rot vom Absatz erben), und .badge gibt dem Label Farbe und Hintergrund. Die Überschriften sind auch #222: Sie erben von #catalog.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Das HTML-Dokument · Formulare
- Geht weiter in: Das Box-Modell · Flexbox: Reihe und Spalte · Grid: Zeilen und Spalten · Responsive Design
- Aufgaben zum Thema: CSS: Wie die Seite aussieht