Modernes CSS
CSS hat sich in den letzten Jahren stärker verändert als im Jahrzehnt davor. Dieses Kapitel zeigt drei Neuerungen, die den Alltag spürbar einfacher machen, und einen Blick nach vorn.
Was du am Ende kannst
Abschnitt betitelt „Was du am Ende kannst“- mit
:has()ein Element abhängig von seinem Inhalt gestalten - CSS übersichtlich verschachteln
- einen Dunkelmodus mit wenigen Zeilen bauen
- neuere Funktionen richtig einordnen
Live-Coding zum Mitmachen
⤓ demo-20-modernes-css.zip herunterladenDer Ordner starter ist der Ausgangsstand, fertig der Stand nach dem Live-Coding.
Enthält: index.html, stil.css
Bisher konnte CSS nur nach unten schauen. :has() wählt ein Element danach aus, was es enthält. Man nennt es auch den
Elternselektor.
.karte { margin-bottom: 0.5rem; padding: 0.5rem; background: #e0e7ff; }.karte:has(input:checked) { background: #dcfce7; text-decoration: line-through; }form:has(:invalid) button { opacity: 0.5; }<div class="karte"><label><input type="checkbox"> Kreuze mich an: Die Karte reagiert</label></div><div class="karte"><label><input type="checkbox"> Mich auch</label></div>.karte:has(input:checked) { … } /* Karte mit angekreuzter Checkbox */.spalte:has(.neu) { … } /* Spalte, in der eine neue Karte liegt */form:has(:invalid) button { … } /* Button in einem Formular mit Fehlern */h2:has(+ p) { … } /* h2, auf die direkt ein Absatz folgt */Vieles davon brauchte früher JavaScript.
Zwei Verwandte: :is(h1, h2, h3) a kürzt Selektorlisten ab, und :where() tut dasselbe, ohne Spezifität hinzuzufügen.
Nesting
Abschnitt betitelt „Nesting“Zusammengehörige Regeln dürfen ineinander stehen. Das & steht für den äußeren Selektor.
.karte { padding: 0.5rem; background: #e0e7ff;
& h4 { margin: 0; color: #312e81; }
&:hover { background: #c7d2fe; }
@media (min-width: 30rem) { padding: 1rem; }}<div class="karte"><h4>Verschachtelt</h4>Fahre mit der Maus darüber.</div>Verschachtle höchstens zwei bis drei Ebenen. Jede Ebene erhöht die Spezifität, und tiefe Nester lassen sich schlecht überschreiben.
Dunkelmodus
Abschnitt betitelt „Dunkelmodus“Dank Custom Properties ist er beinahe geschenkt: Du tauschst die Variablen, und alles andere folgt.
:root { --grund: #fff; --text: #1c2330; --akzent: #4338ca; }@media (prefers-color-scheme: dark) { :root { color-scheme: dark; --grund: #12131c; --text: #e6e8ef; --akzent: #818cf8; }}body { background: var(--grund); color: var(--text); }a { color: var(--akzent); }<p>Stelle dein System auf hell oder dunkel, und diese Fläche folgt. <a href="#">Auch die Links</a>.</p>color-scheme: darkfärbt auch Bildlaufleisten und Formularelemente passend ein.- Prüfe den Kontrast in beiden Modi neu. Eine Farbe, die auf Weiß funktioniert, muss das auf Schwarz nicht.
- Nimm kein reines Schwarz und kein reines Weiß, weiche Töne strengen weniger an.
- Testen: DevTools, Rendering, Emulation von
prefers-color-scheme.
Ein Schalter auf der Seite braucht zusätzlich etwas JavaScript. Das ist eine Aufgabe „Für Schnelle“ im nächsten Kapitel.
Ausblick: Was gerade kommt
Abschnitt betitelt „Ausblick: Was gerade kommt“| Funktion | Wofür | Heute |
|---|---|---|
| Anchor Positioning | Element an ein anderes heften, etwa für Tooltips | mit @supports |
| Scroll-driven Animations | Animation folgt dem Scrollen | mit @supports |
@scope |
Regeln auf einen Bereich begrenzen | mit @supports |
popover |
Aufklappendes ohne JavaScript | prüfen, ob es die Zielgruppe hat |
light-dark() |
zwei Farben in einem Wert für hell und dunkel | bald überall sicher |
@supports (anchor-name: --marke) { .tooltip { position: absolute; position-anchor: --marke; top: anchor(bottom); }}Live-Coding: Erledigte Karten und Dunkelmodus
Abschnitt betitelt „Live-Coding: Erledigte Karten und Dunkelmodus“/* :has() – das Elternelement reagiert auf sein Kind */.karte:has(input:checked) { opacity: 0.6;}
.karte:has(input:checked) h3 { text-decoration: line-through;}
.spalte:has(.neu) h2::after { content: " •"; color: var(--farbe-akzent);}
/* Nesting – zusammengehörige Regeln stehen zusammen */.erledigt { margin-top: var(--abstand-s); font-size: 0.875rem;
& label { display: inline-flex; align-items: center; gap: 0.4rem; min-height: 2.75rem; cursor: pointer; }
& input { width: 1.25rem; height: 1.25rem; accent-color: var(--farbe-akzent); }}
/* Dunkelmodus – nur die Variablen wechseln, alles andere folgt */@media (prefers-color-scheme: dark) { :root { color-scheme: dark; --farbe-text: #e6e8ef; --farbe-text-leise: #a4abba; --farbe-akzent: #818cf8; --farbe-akzent-dunkel: #1e1b4b; --farbe-flaeche: #12131c; --farbe-karte: #232533; --farbe-linie: #3a3e52; --farbe-spalte: #1a1c28; }
.seitenleiste a[aria-current="page"], .knopf:not(.leise), .neu { color: #12131c; }
select { background-color: var(--farbe-karte); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23e6e8ef'/%3E%3C/svg%3E"); color: var(--farbe-text); }
a { color: var(--farbe-akzent); }
.seitenleiste a, .reiter a { color: inherit; }}Starter für die Übung
⤓ uebung-20-modernes-css.zip herunterladenZIP-Datei entpacken und den Ordner in VS Code öffnen (Datei → Ordner öffnen).
Enthält: index.html, profil.html, stil.css, uebung.css
Die Seite profil.html enthält ein Formular. Schreibe deine Regeln in uebung.css.
Stufe 1: Nesting
Abschnitt betitelt „Stufe 1: Nesting“Gestalte .profil und die enthaltenen Felder und den Knopf in einem verschachtelten Block.
Stufe 2: Fehler anzeigen
Abschnitt betitelt „Stufe 2: Fehler anzeigen“Jedes .feld enthält eine versteckte .fehler-Meldung. Sie erscheint nur, wenn das Feld ausgefüllt, aber ungültig ist. Das
leere placeholder=" " ist ein Kniff, mit dem du per :placeholder-shown erkennst, ob schon etwas eingetragen wurde.
Stufe 3: Abhängige Felder
Abschnitt betitelt „Stufe 3: Abhängige Felder“Das Feld „Wie oft?“ erscheint nur, wenn der Newsletter angekreuzt ist, und zwar ohne JavaScript.
Für Schnelle
Abschnitt betitelt „Für Schnelle“Prüfe die Seite im Dunkelmodus. Was stimmt nicht mehr? Korrigiere es.