mitmario.dev

Einen Stilkonflikt auflösen

CSS Im Browser 4 Min Lesezeit 3 BeispieleLektion 5 von 6

Im Alltag klingt das Problem immer gleich. Es passiert nichts. Eine Regel steht da, und die Seite sieht aus wie vorher. Meist steckt eine von drei Ursachen dahinter, und die kannst du in einer festen Reihenfolge abfragen. Dafür brauchst du alles aus diesem Abschnitt.

Der Selektor trifft nicht

Bevor irgendetwas anderes zählt, muss die Regel überhaupt bei einem Element ankommen.

Frage eins, der Selektor trifft nicht
/* Ein einziger Buchstabe zu viel. Die Regel ist vollkommen
   in Ordnung, sie meint nur etwas, das es nicht gibt. */
.projekte h3 {
  color: #b91c1c;
}

/* Und hier stimmt der Name, aber die Ebene nicht: das
   Größer-Zeichen verlangt ein direktes Kind, der Absatz
   steht eine Ebene tiefer. Nimm das Zeichen testweise
   heraus, dann wird er rot. */
.projekt > p {
  color: #b91c1c;
}

Zwei klassische Fälle stehen hier nebeneinander. Einmal ein Tippfehler im Klassennamen, der beim Lesen nicht auffällt, weil projekte genauso plausibel aussieht wie projekt. Und einmal ein Kombinator, der ein direktes Kind verlangt, obwohl das gemeinte Element eine Ebene tiefer steht.

Im Reiter „Regeln“ steht so eine Regel blass da, mit dem Vermerk „Selektor trifft nicht“. An der Überschrift gewinnt keine einzige Regel. Die Liste besteht nur aus den beiden blassen, .projekte h3 und .projekt > p, beide mit 0-1-1. Sie sind also nicht kaputt und nicht zu schwach, sie meinen etwas anderes.

Die Deklaration ist ungültig

Der Selektor trifft, aber der Browser hat die Zeile weggeworfen, und zwar leise, wie in Lektion 1.4.

Frage zwei, die Deklaration ist ungültig
.projekt {
  /* Zahl ohne Einheit: diese Zeile wird verworfen. */
  padding: 24;

  /* Der Rest der Regel bleibt aber stehen. */
  background-color: #f4f4f5;
}

.projekt h3 {
  /* Fehlendes Semikolon: nimmt die nächste Zeile mit. */
  color: #b91c1c
  font-size: 24px;
}

Im Beispiel stehen drei solche Zeilen, eine Zahl ohne Einheit, ein Wert, den es für diese Eigenschaft nicht gibt, und ein fehlendes Semikolon, das die nächste Zeile mit in den Abgrund reißt.

Im Reiter fehlt die Zeile dann einfach. An der Karte steht unter .projekt nur background-color. Von padding: 24 ist nichts zu sehen, nicht einmal durchgestrichen. An der Überschrift fehlt sogar die ganze Regel .projekt h3, weil dort beide Zeilen verlorengegangen sind und eine leere Regel gar nicht erst angezeigt wird. Der Rest der ersten Regel wirkt ganz normal. Gerade das macht diesen Fall so verwirrend, denn die halbe Regel funktioniert ja.

Die Entwicklerwerkzeuge deines Browsers lesen den Rohtext mit und zeigen eine verworfene Zeile deshalb durchgestrichen und mit einem Warnsymbol.

Eine andere Regel gewinnt

Erst jetzt ist die Kaskade dran. Der Selektor trifft, die Deklaration ist gültig, und trotzdem siehst du nichts, weil eine andere Regel dieselbe Eigenschaft anders setzt.

Frage drei, eine andere Regel gewinnt
.projekt {
  border-radius: 12px;
  border: 2px solid #b91c1c;
  padding: 16px;
}

/* Gleich stark, steht aber später: die Ecken bleiben eckig.
   Schieb den Block nach oben und die Rundung kommt zurück. */
.kasten {
  border-radius: 0;
}

Dann zählt, welche Stufe der Kaskade entschieden hat, denn die Gegenmittel sind verschieden. Bei gleicher Spezifität ist es die Reihenfolge, und der Block wandert. Bei ungleicher Spezifität wird nachgerechnet und nur so weit erhöht wie nötig. Bei Layern steht die Antwort in der Deklarationszeile.

Im Reiter ist die Zeile durchgestrichen, und daneben steht, wer sie geschlagen hat. Im Beispiel steht .kasten oben, darunter .projekt mit dem Vermerk border-radius überstimmt von der späteren Regel, und beide tragen 0-1-0. Der Vermerk nennt also die Stufe, auf der die Regel verloren hat. Steht dort „überstimmt durch höhere Spezifität“ samt Zahl, war es die dritte Stufe. Steht „überstimmt aus @layer …“, war es die zweite, und die Antwort steht in der Deklarationszeile. Steht „überstimmt durch !important“, hat jemand die Notbremse gezogen.

Warum die Reihenfolge der Fragen zählt

Die drei Fragen sehen aus, als könnte man sie in beliebiger Folge stellen. Das geht nicht, und der Grund ist praktisch.

Fängst du mit der dritten an, drehst du an der Spezifität. Der Selektor wird länger, dann kommt ein !important dazu, und irgendwann siehst du vielleicht sogar eine Wirkung. Nur war die Ursache ein Tippfehler, und übrig bleibt eine Regel, die aus den falschen Gründen funktioniert.

Deshalb gehe ich immer von oben nach unten. Trifft der Selektor, ist die Zeile gültig, und erst dann, wer gewinnt. Die ersten beiden Fragen sind schnell beantwortet.

Im Reiter „Regeln“ sehen die drei verschieden aus, und das ist der schnellste Weg durch die Reihenfolge. Blass heißt, der Selektor trifft nicht. Eine fehlende Zeile heißt, die Deklaration war ungültig. Durchgestrichen mit Vermerk heißt, eine andere Regel gewinnt.

Selten bleiben alle drei Fragen ohne Befund. Dann trifft die Zeile, ist gültig und gewinnt, und das Element kann trotzdem nichts mit ihr anfangen. Ein width an einem span ist so ein Fall. Warum, steht in Abschnitt 4.

In Lektion 16.3 gehst du den Ablauf noch einmal an einer Seite mit vier echten Fehlern durch, wenn genug Eigenschaften dazugekommen sind und es sich lohnt. In der Aufgabe fehlen an einer Karte drei Dinge, jedes aus einem anderen Grund.

Zum Mitnehmen

Tut eine Regel nichts, frage ich in dieser Reihenfolge, ob der Selektor trifft, ob die Deklaration gültig ist und ob eine andere Regel gewinnt. Im Reiter Regeln heißt das blass, fehlende Zeile oder durchgestrichen.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

Was in dieser Lektion steckt

  • Artikel mit 3 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe im Editor, direkt im Browser geprüft

    Öffnet sich mit dem Basis Konto.