Lege Textstandards für die Seite auf body fest, lass geerbte Eigenschaften in Komponenten fließen und richte Layoutregeln gezielt aus. Diese Anleitung zeigt, wie du auf einem Mac eine lokale HTML-Seite erstellst und überprüfst, ohne jedes Element eine universelle Regel rückgängig machen zu lassen.

Warum stört eine universelle Regel die Standardwerte von Komponenten?

Der universelle Selektor * trifft auf jedes Element zu. Eine Deklaration innerhalb dieser Regel gilt daher direkt für jedes passende Element; sie stellt nicht lediglich einen Wert bereit, den Nachfahren erben können. Pseudoelemente trifft sie ebenfalls nicht direkt; dafür sind Selektoren wie *::before erforderlich. Universelle Selektoren.

Betrachte diesen CSS-Ausschnitt für eine Komponente mit einem Absatz und einem darin verschachtelten Text-Span:

/* Illustrative fragment: assumes a .tile with text descendants. */
* {
  color: #303840;
}

.tile {
  color: #245d75;
}

Das Tile selbst erhält die blaue Textfarbe. Sein Absatz und Span erhalten direkt die dunkle Farbe aus der universellen Regel. Die Komponentenfarbe kann diese Deklarationen nicht durch gewöhnliche Vererbung durchdringen. Nach den CSS-Standardwertregeln erhalten geerbte Eigenschaften den berechneten Wert des Elternelements, wenn die Kaskade für diese Eigenschaft am Element keinen Wert bereitstellt. CSS Cascading and Inheritance Level 4, Standardwertbildung.

Das kann verwirrend sein, weil * keine Spezifität hat. Die Spezifität vergleicht konkurrierende Deklarationen auf demselben Element innerhalb des jeweils geltenden Kaskadenursprungs und der Kaskadenschicht. Eine Deklaration auf einem Elternelement ist kein konkurrierender Selektortreffer auf dessen Kind. Den Selektor des Elternelements spezifischer zu machen, löst dieses Vererbungsproblem daher nicht. Spezifität.

Die hilfreiche Änderung besteht darin, die universelle Textdeklaration zu entfernen und den Standardwert auf body festzulegen. Nachfahren können ihn dann erben, bis eine Komponente oder ein Element einen anderen Wert festlegt. MDN führt color als vererbte Eigenschaft auf und erklärt, dass die Vererbung dem berechneten Wert des Elternelements folgt. Vererbung.

Welche Standardwerte gehören auf die Seite, in eine Komponente oder auf jedes Element?

Bevor du einen breit gefassten Selektor schreibst, entscheide, ob die Eigenschaft durch einen Textbereich vererbt werden, eine einzelne Box beschreiben oder eine gezielte Regel für alle Boxen festlegen soll. Die folgende Entscheidungshilfe wendet diese Unterscheidung auf eine kleine, selbst erstellte Seite an.

Gewünschtes Ergebnis Empfohlene Platzierung Grund
Gewöhnlicher Seitentext hat eine gemeinsame Grundfarbe und Typografie body Gibt Text durch Vererbung einen gemeinsamen Ausgangswert
Ein Tile und sein gewöhnlicher Text haben dieselbe abweichende Farbe .tile Legt innerhalb dieser Komponente einen neuen vererbbaren Wert fest
Eine einzelne Bildunterschrift hat eine andere Farbe .caption Wendet die Ausnahme auf das benötigte Element an
Ein einzelnes Bedienfeld hat Innenabstand, Rahmen oder Hintergrund Die Klasse des Bedienfelds Verknüpft die Box-Dekoration mit ihrem Träger
Für Boxen gilt ein einheitliches Größenmodell Eine gezielte Regel für box-sizing Legt eine ausdrückliche Größenkonvention fest
Für Überschriften gilt ein leicht ersetzbarer Standardabstand Ein gezielter Überschriftselektor, optional umschlossen von :where() Beschränkt den Standardwert auf die vorgesehenen Elemente

Vererbung hängt von der jeweiligen Eigenschaft ab. Sieh im Eigenschaftsverzeichnis unter Inherited nach, statt anzunehmen, dass jede Deklaration auf body an Nachfahren weitergegeben wird. Rahmen werden beispielsweise standardmäßig nicht vererbt. Vererbung.

Eine universelle Größenregel kann dennoch sinnvoll sein. Mit border-box umfasst die deklarierte Breite eines Elements auch Innenabstand und Rahmen; Außenabstände bleiben außerhalb dieser Breite. Das ist eine gezielte Entscheidung zum Boxmodell und kein Grund, alle Seitenstandardwerte universell anzuwenden. box-sizing.

Erstelle eine vollständige lokale Demo auf deinem Mac

Verwende TextEdit im Nur-Text-Modus oder einen vorhandenen Code-Editor. Wähle in TextEdit Ablage > Neu und dann Format > In reinen Text umwandeln. Füge das vollständige Dokument unten ein, wähle Ablage > Sichern und nenne die Datei page-defaults.html. Wähle bei entsprechender Aufforderung Use .html. Apple beschreibt diesen Ablauf in der HTML-Anleitung zu TextEdit.

Dieses Beispiel verwendet synthetische Beschriftungen und mit CSS gezeichnete Formen. Es ist ein vollständiges Dokument mit eingebettetem Stylesheet, sodass keine weiteren Dateien vorbereitet werden müssen. Der Code wurde hier überprüft; seine Darstellung wurde nicht in einem Mac-Browser ausgeführt.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Page defaults demonstration</title>
  <style>
    *, *::before, *::after {
      box-sizing: border-box;
    }

    body {
      margin: 0;
      font-family: system-ui, sans-serif;
      font-size: 1rem;
      line-height: 1.5;
      color: #303840;
      background-color: #f4f5f6;
    }

    main {
      max-width: 44rem;
      margin: 0 auto;
      padding: 2rem 1rem;
    }

    h1 {
      line-height: 1.2;
    }

    .tile {
      margin: 1.5rem 0;
      padding: 1.25rem;
      border: 2px solid currentColor;
      border-radius: 0.75rem;
      color: #245d75;
      background-color: #ffffff;
    }

    .tile h2 {
      margin-top: 0;
    }

    .shape {
      width: 4rem;
      height: 4rem;
      background-color: currentColor;
    }

    .shape--round {
      border-radius: 50%;
    }

    .caption {
      color: #66523c;
    }
  </style>
</head>
<body>
  <main>
    <h1>Shape notes</h1>
    <p>Page sample: <span>Label A</span>.</p>

    <section class="tile">
      <h2>Tile B</h2>
      <div class="shape shape--round" aria-hidden="true"></div>
      <p>Component sample: <span>Label C</span>.</p>
      <p class="caption">Caption D has its own text color.</p>
    </section>

    <p>Page sample: <span>Label E</span>.</p>
  </main>
</body>
</html>

Öffne page-defaults.html in deinem Browser. Wenn du den Quelltext in TextEdit erneut öffnest, wähle TextEdit > Einstellungen > Öffnen und Sichern und aktiviere HTML-Dateien als HTML-Code statt als formatierten Text anzeigen, damit TextEdit das Markup einheitlich anzeigt. Mit HTML-Dokumenten in TextEdit auf dem Mac arbeiten.

Prüfe mit drei Änderungen, wo die Vererbung endet

Mit diesen Prüfungen wird das Dokument zu einer kleinen Diagnoseübung. Speichere den Quelltext und lade den Browser nach jeder Änderung neu. Behalte eine Kopie des ursprünglichen Dokuments oder mache jede Änderung rückgängig, bevor du die nächste ausprobierst.

  1. Ändere nur die Farbe von body zu #4b465f. Der Text um Label A und Label E sollte sich ändern. Das Tile behält seine eigene Farbe.
  2. Stelle die Seitenfarbe wieder her und ändere dann nur .tile zu color: #526637. Der gewöhnliche Überschriften- und Absatztext sollte dieser Änderung folgen, einschließlich Label C. Caption D behält seine ausdrücklich festgelegte Farbe.
  3. Stelle die Tile-Farbe wieder her und füge dann vorübergehend * { color: #303840; } am Anfang des Stylesheets ein. Der Absatz mit Label C erhält nun diese direkte Deklaration. Entferne die vorübergehende Regel anschließend wieder.

Die Prüfungen veranschaulichen den Unterschied zwischen einer Komponente, die einen vererbbaren Wert festlegt, und einem Nachfahren, der eine eigene Deklaration erhält. Das erwartete Textverhalten folgt den Regeln zur Vererbung und Standardwertbildung der Spezifikation.

Welche Vereinbarung gilt zwischen der HTML-Seite und ihrem Stylesheet?

Halte das Laden von Ressourcen und das Verhalten von Selektoren getrennt. Das Beispiel bettet sein CSS in ein Element style ein. Wenn du ein separates Stylesheet bevorzugst, verschiebe nur den Inhalt dieses Elements in eine Nur-Text-Datei namens page-defaults.css, die neben der HTML-Datei gespeichert wird. Ersetze das gesamte Element style innerhalb von head durch die folgende Zeile. Dies ist ein Ersatzfragment und kein weiteres vollständiges Dokument.

<link rel="stylesheet" href="page-defaults.css">

Der Linktyp stylesheet kennzeichnet eine externe CSS-Ressource, die zur Darstellung des Dokuments verwendet wird. Der Dateiname in href muss auf die Datei verweisen, die du tatsächlich gespeichert hast; die Deklaration erstellt diese Datei nicht. Der HTML-Standard definiert diese Beziehung unter Linktyp: stylesheet.

Für dieses Beispiel ist die Vereinbarung einfach: Das HTML stellt Elemente und Klassen bereit, während das CSS deren Darstellung festlegt. Wenn du .tile im Stylesheet umbenennst, musst du die zugehörige Klasse im HTML aktualisieren. Wenn du die CSS-Datei verschiebst, musst du ihren Ressourcenverweis aktualisieren. Für keine der beiden Änderungen brauchst du einen spezifischeren Selektor.

Wenn die externe Version ohne Formatierung erscheint, überprüfe zuerst, ob die CSS-Datei unter dem erwarteten Namen existiert und ob ihr Inhalt CSS statt des umgebenden HTML-Dokuments enthält. Kehre zur eingebetteten Version zurück, um Fehler beim Laden von Ressourcen einzugrenzen, bevor du die Kaskade änderst.

Wann solltest du :where() oder Kaskadenschichten verwenden?

Verwende diese Funktionen, wenn sie ein zusätzliches Problem lösen. Das vollständige Beispiel oben benötigt keine davon.

Verwende :where() für gezielte Standardwerte ohne Spezifität

Angenommen, die Seite enthält später mehrere Überschriftenebenen. Dieser optionale Stylesheet-Ausschnitt legt gemeinsame Abstände fest, die sich leicht durch gewöhnliche Überschriftselektoren ersetzen lassen:

/* Optional fragment: add to the example stylesheet. */
:where(h1, h2, h3) {
  margin-bottom: 0.75rem;
}

h2 {
  margin-bottom: 1rem;
}

Der gesamte Selektor :where() hat keine Spezifität, einschließlich seiner Argumente. * durch :where(*) zu ersetzen, behebt jedoch nicht das vorherige Farbproblem: Der Selektor trifft weiterhin auf jedes Element zu und weist ihm eine direkte Deklaration zu. Dieses Problem lässt sich durch Vererbung lösen. MDN dokumentiert :where() als seit Januar 2021 browserübergreifend breit verfügbar; prüfe die Kompatibilitätstabelle, wenn du einen älteren Browser unterstützen musst. Die Pseudoklasse :where().

Wenn ein Browser :where() nicht unterstützt, kannst du für diese Abstandswerte eine gewöhnliche Selektorliste wie h1, h2, h3 verwenden und gleich spezifische Ausnahmen später im selben Stylesheet und derselben Kaskadenschicht platzieren. So bleiben die Standardwerte gezielt, auch wenn sie keine Spezifität von null mehr haben. Spezifität.

Verwende Schichten, wenn Regelgruppen eine festgelegte Reihenfolge brauchen

Für ein größeres Stylesheet zeigt dieser optionale Ausschnitt eine deklarierte Reihenfolge der Schichten. Er ergänzt das vollständige Beispiel, ersetzt aber nicht dessen gesamtes CSS.

/* Optional fragment for browsers supporting cascade layers. */
@layer defaults, components;

@layer defaults {
  p {
    margin-bottom: 1rem;
  }
}

@layer components {
  .tile p {
    margin-bottom: 0.5rem;
  }
}

Bei normalen Autorendeklarationen haben spätere Schichten Vorrang vor früheren; normale Deklarationen ohne Schicht haben Vorrang vor Deklarationen in Schichten. Wichtige Deklarationen kehren die Schichtenreihenfolge um. Wenn du also !important hinzufügst, ändert sich diese Anordnung. Schichten ordnen konkurrierende Regeln; sie sorgen nicht dafür, dass ein direkt formatiertes Kind den Wert seines Elternelements erbt. Die At-Regel @layer.

MDN dokumentiert die browserübergreifende Verfügbarkeit von @layer seit März 2022. Wenn ein älterer Zielbrowser die Funktion nicht unterstützt, halte wichtige Formatierungen außerhalb von Schichtblöcken und verwende den Ansatz ohne Schichten aus dem vollständigen Beispiel. Lege erforderliche Formatierungen nicht ausschließlich in einer nicht unterstützten Funktion ab. Unterstützung von Kaskadenschichten.

Wie behebst du ein vorhandenes Stylesheet, ohne weitere Überschreibungen hinzuzufügen?

Gehe Eigenschaft für Eigenschaft vor. Suche bei einem Problem mit der Textfarbe die breit gefasste Regel, die Nachfahren direkt diese Farbe zuweist. Entferne die Deklaration aus der universellen Regel, lege den Seitenwert auf body fest und platziere Komponentenfarben auf den Wurzelelementen der Komponenten. Behalte Deklarationen auf Elementebene nur dort bei, wo das Design eine Ausnahme erfordert.

Wiederhole anschließend die drei Änderungen aus der Demo. Wenn gewöhnlicher Komponententext weiterhin nicht dem Elternelement folgt, suche nach einer Deklaration, die auf diesen Nachfahren zielt. Wenn sich durch eine Änderung des Rahmens einer Komponente die Rahmen ihrer Nachfahren nicht ändern, ist das erwartungsgemäß: Rahmen werden anders vererbt als Textfarben. Vererbung.

Ein wartbarer Standardwert hat einen klaren Zuständigkeitsbereich. Lege Typografie der Seite an der Seitengrenze fest, die Darstellung der Komponente an der Komponentengrenze und gezielte Ausnahmen auf den Elementen, die sie benötigen. Beschränke universelle Deklarationen auf Entscheidungen, die tatsächlich für jedes passende Element gelten sollen, und überprüfe diese Grenzen mit einer kleinen lokalen Seite.

Quellen