Vom bis hielt die CSS Working Group (CSSWG) ihr zweites Präsenztreffen des Jahres in Coruña, Spanien, ab, mit einer langen Agenda an neuen Funktionen und Verbesserungen für die Sprache. Wenn uns 2023 unglaubliche Fortschritte wie natives Nesting, Container und Style Queries oder den has:-Selektor bescherte, dann wird 2024 noch vollgepackter mit noch bahnbrechenderen Neuerungen. Ob eine neue Funktion wie Inline-Conditionals gerade erst beginnt oder Langzeitprojekte zum Abschluss kommen – 2024 ist bereits voller spannender Entwicklungen, und wir haben erst Juli!
Ich wollte teilen, was meiner Meinung nach einige der interessantesten und bedeutendsten kommenden CSS-Funktionen sind, die bei dem Treffen untersucht wurden. Ich möchte jedoch nicht, dass Sie das Folgende als exakte Zusammenfassung der Diskussionen verstehen. Stattdessen möchte ich die allgemeineren Themen ansprechen, die im Mittelpunkt des letzten Treffens standen. In der Realität köcheln die untersuchten Funktionen oft schon seit Jahren, und die Diskussionen sind eher auf spezifische Fälle und neue Erweiterungen ausgerichtet, als auf die Definition einer ganzen Spezifikation; eine Arbeit, die in einem einzigen Treffen unmöglich wäre.
Die genauen besprochenen Themen finden Sie auf der Agenda des CSSWG-Meetings.
Feature 1: Was wäre, wenn wir if() bekämen?
Seit CSS Custom Properties um 2016 eine zuverlässige Unterstützung erhielten, gab es viele Versuche, bestimmte Stile in Abhängigkeit von einem Wert einer Custom Property anzuwenden, ohne natürlich auf JavaScript zurückzugreifen. Einer der frühesten Workarounds für bedingte Stile wurde 2016 von Roman Komarov in „Conditions for CSS Variables“ veröffentlicht. Seitdem wurden viele andere Hacks für bedingte Deklarationen in CSS dokumentiert (einschließlich dieses extrem cleveren von Ana Tudor hier auf CSS-Tricks). Tatsächlich finden Sie eine vollständige Liste, die diese Workarounds diskutiert und vergleicht, von CSSWG-Mitglied Lea Verou in ihrem aktuellen Artikel „Inline conditionals in CSS, now?“.
Sicher ist, dass die Community sich nach einer bedingten Möglichkeit sehnt, Stile mittels Custom Properties anzuwenden. Heute haben wir eine Spezifikation für Style Queries, die diese Aufgabe bewältigen kann, aber sie bringt Einschränkungen mit sich, die nicht mit der Browserunterstützung zusammenhängen. Die größte dieser Einschränkungen? Wir können den abgefragten Container nicht direkt stylen, daher benötigen wir im HTML eine Art Wrapper-Element um diesen Wrapper.
<div class="news-container" style="--variant: info">
<p>Here is some good <strong>news</strong></p>
</div>
…zusätzlich zum Schreiben der Style Query
.news-container {
container-name: news-container;
}
@container news-container style(--variant: info) {
p {
color: blue;
border: 1px solid blue;
}
}
Wie if() aussehen könnte
Seitens der CSSWG gibt es bereits seit 2018 Diskussionen über das Hinzufügen einer if()-Funktion. Am dieses Jahres – ja, sechs Jahre später – beschloss die CSSWG, mit der Arbeit an if() für CSS zu beginnen. So gut es auch klingen mag, erwarten Sie if() in den nächsten zwei Jahren nicht in einem Browser! (Das ist Leas inoffizielle Schätzung.) Wir werden wahrscheinlich noch länger warten müssen, bis die Browserunterstützung ausreicht, um es zuverlässig in der Produktion einzusetzen. Der Spezifikationsentwurf fängt gerade erst an, und viele Dinge müssen erst Tests bestehen. Zum Vergleich: Der Arbeitsentwurf für CSS-Variablen begann 2012 und erhielt erst 2016 eine breite Browserunterstützung.
Was die Syntax betrifft, wird if() wahrscheinlich den Ternär-Operator von JavaScript und anderen Programmiersprachen übernehmen, strukturiert wie folgt:
if(a ? b : c)
…wobei a die Custom Property ist, die wir prüfen, und b sowie c die möglichen bedingten Rückgabewerte sind. Um Stile zu prüfen, würde ein Inline-style(--my-property: value) verwendet.
.forecast {
background-color: if(style(--weather: clouds) ? var(--clouds-color): var(--default-color));
}
Auch wenn ? in CSS bisher nicht verwendet wird und : überall sonst eine andere Bedeutung hat, denke ich, dass dies die Syntax ist, mit der die meisten vertraut sind, ganz zu schweigen davon, dass sie auch eine nahtlose bedingte Verkettung ermöglicht.
.forecast {
background-color: if(
style(--weather: clouds) ? var(--clouds-color):
style(--weather: sunny) ? var(--sunny-color);
style( --weather: rain) ? var(--rain-color): var(--default-color)
);
}
Zukünftige if()-Verbesserungen
Obwohl diese es wahrscheinlich nicht in die erste Version schaffen werden, ist es interessant zu sehen, wie sich if() zwischen jetzt und einem späteren Zeitpunkt verändern könnte:
- Unterstützung für andere Inline-Conditionals. Wir sollen Custom Properties über die
style()-Query prüfen, könnten aber ebenso Media-Features mit einer Inline-media()-Query oder die Unterstützung einer spezifischen Eigenschaft durch den User-Agent mit einem Inline-support()abfragen.
.my-element {
width: if(media(width > 1200px) ? var(--size-l): var(--size-m));
}
- Verwendung von Bedingungen innerhalb anderer CSS-Funktionen. In zukünftigen Entwürfen könnten wir Ternär-Ausdrücke innerhalb anderer Funktionen verwenden, ohne sie in
if()einschließen zu müssen, z. B. so wie wir Berechnungen ohnecalc()durchführen können, wenn wir uns innerhalb einerclamp()- oderround()-Funktion befinden.
Feature 2: Dokumentübergreifende View Transitions
Letztes Jahr gab uns die View Transition API die Möglichkeit, nahtlose Übergänge beim Navigieren zwischen Webseiten und Zuständen zu erstellen. Keine Komponenten oder Frameworks, keine Animationsbibliotheken – nur pures HTML und CSS mit einer Prise JavaScript. Die erste Implementierung von View Transitions wurde vor einer Weile in die Browser integriert, basierte aber auf einer experimentellen, von Chrome definierten Funktion und war auf Übergänge zwischen zwei Zuständen (Single-Page View Transitions) beschränkt, ohne Unterstützung für Übergänge zwischen verschiedenen Seiten (d. h. Multi-Page View Transitions), wonach die meisten Entwickler schreien. Die Möglichkeiten, das Verhalten nativer Apps nachzuahmen, sind aufregend!
Deshalb ist das CSS View Transitions Module Level 2 so großartig und mein Favorit unter allen CSS-Neuerungen in diesem Artikel. Ja, das Feature bringt native, nahtlose Übergänge zwischen Seiten, aber der eigentliche Clou ist, dass kein Framework mehr dafür nötig ist. Anstatt eine Bibliothek zu verwenden – sagen wir React + eine Routing-Bibliothek – können wir zu einfachem CSS und JavaScript zurückkehren.
Natürlich gibt es Komplexitätsstufen, bei denen die View Transition API an ihre Grenzen stoßen mag, aber sie ist ideal für unzählige Fälle, in denen wir einfach nur Seitenübergänge ohne die Performance-Kosten eines Frameworks wünschen.
Aktivierung von View Transitions
View Transitions werden ausgelöst, wenn wir zwischen zwei Seiten derselben Herkunft (Origin) navigieren. In diesem Kontext kann Navigation das Klicken eines Links, das Absenden eines Formulars oder das Vor- und Zurückgehen mit den Browser-Buttons sein. Im Gegensatz dazu wird beispielsweise die Verwendung einer Suchleiste zwischen Seiten derselben Herkunft keinen Seitenübergang auslösen.
Beide Seiten – die, von der wir weg navigieren, und die, zu der wir navigieren – müssen die Transition über die At-Rule @view-transition aktivieren und die Eigenschaft navigation auf auto setzen.
@view-transition {
navigation: auto;
}
Wenn beide Seiten zustimmen, erstellt der Browser einen „Snapshot“ beider Seiten und blendet die „Vorher“-Seite sanft in die „Nachher“-Seite über.
Übergang zwischen „Snapshots“
In diesem Video sehen Sie, wie die alte Seite in die neue Seite übergeht. Das funktioniert dank eines ganzen Baums neuer Pseudo-Elemente, die während des Übergangs bestehen bleiben und CSS-Animationen verwenden, um den Effekt zu erzeugen. Der Browser gruppiert Snapshots von Elementen mit einer eindeutigen view-transition-name-Eigenschaft, die eine eindeutige Kennung für den Übergang festlegt, auf die wir uns beziehen können. Diese wird im Pseudo-Element ::view-transition erfasst, das alle Übergänge auf der Seite hält.
Man kann sich ::view-transition als das :root-Element für alle Seitenübergänge vorstellen, das alle Teile einer View Transition in derselben Standardanimation gruppiert.
::view-transition
├─ ::view-transition-group(name)
│ └─ ::view-transition-image-pair(name)
│ ├─ ::view-transition-old(name)
│ └─ ::view-transition-new(name)
├─ ::view-transition-group(name)
│ └─ ::view-transition-image-pair(name)
│ ├─ ::view-transition-old(name)
│ └─ ::view-transition-new(name)
└─ /* and so one... */
Beachten Sie, dass jeder Übergang in einer ::view-transition-group lebt, die ein ::view-transition-image-pair enthält, das wiederum aus den „alten“ und „neuen“ Seiten-Snapshots besteht. Wir können so viele Gruppen dort haben, wie wir wollen, und alle enthalten ein Bildpaar mit beiden Snapshots.
Kurzes Beispiel: Verwenden wir die ::view-transition-„Wurzel“ als Parameter, um alle Übergänge auf der Seite auszuwählen und eine Gleitanimation zwischen den alten und neuen Snapshots zu erstellen.
@keyframes slide-from-right {
from {
transform: translateX(100vw);
}
}
@keyframes slide-to-left {
to {
transform: translateX(-100vw);
}
}
::view-transition-old(root) {
animation: 300ms ease-in both slide-to-left;
}
::view-transition-new(root) {
animation: 300ms ease-out both slide-from-right;
}
Wenn wir zwischen Seiten navigieren, gleitet die gesamte alte Seite nach links heraus, während die gesamte neue Seite von rechts hineingleitet. Aber vielleicht möchten wir verhindern, dass einige Elemente auf der Seite am Übergang teilnehmen, damit sie zwischen den Seiten bestehen bleiben, während sich alles andere vom „alten“ zum „neuen“ Snapshot bewegt.
Hier ist die Eigenschaft view-transition-name entscheidend, da wir Snapshots bestimmter Elemente machen und sie in ihre eigene ::view-transition-group packen können, getrennt von allem anderen, sodass sie individuell behandelt werden.
nav {
view-transition-name: navigation;
/*
::view-transition
├─ ::view-transition-group(navigation)
│ └─ ::view-transition-image-pair(navigation)
│ ├─ ::view-transition-old(navigation)
│ └─ ::view-transition-new(navigation)
└─ other groups...
*/
}
Sie können eine Live-Demo davon auf GitHub finden. Beachten Sie jedoch, dass die Browserunterstützung zum Zeitpunkt dieses Artikels auf Chromium-Browser (d. h. Chrome, Edge, Opera) beschränkt ist.
Es gibt viele Dinge, auf die wir uns bei dokumentübergreifenden View Transitions freuen können. Wenn wir beispielsweise mehrere Elemente mit unterschiedlichen view-transition-name haben, könnten wir ihnen eine gemeinsame view-transition-class geben, um ihre Animationen an einer Stelle zu stylen – oder sogar die View Transitions mit JavaScript weiter anpassen, um zu prüfen, von welcher URL die Seite kommt, und entsprechend zu animieren.
Feature 3: Anchor Positioning
Ein Element relativ zu einem anderen Element in CSS zu positionieren, scheint eine dieser kinderleichten, unkomplizierten Aufgaben zu sein, erfordert aber in der Realität das Hantieren mit Inset-Eigenschaften (top, bottom, left, right) basierend auf einer Reihe von „magischen Zahlen“, um alles genau richtig hinzubekommen. Zum Beispiel könnte ein kleiner Tooltip, der links von einem Element erscheint, wenn man darüber fährt, im HTML so aussehen:
<p class="text">
Hover for a surprise
<span class="tooltip">Surprise! I'm a tooltip</span>
</p>
…und in CSS mit aktuellen Ansätzen:
.text {
position: relative;
}
.tooltip {
position: absolute;
display: none;
/* vertical center */
top: 50%;
transform: translateY(-50%);
/* move to the left */
right: 100%;
margin-right: 15px; */
}
.text:hover .tooltip {
display: block;
}
Die Positionierung und die Inset-Werte des Elements ändern zu müssen, ist nicht der Weltuntergang, aber es fühlt sich definitiv so an, als gäbe es einen einfacheren Weg. Außerdem ist der Tooltip im letzten Beispiel extrem fragil; wenn der Bildschirm zu klein oder unser Element zu weit links ist, wird der Tooltip versteckt oder ragt über den Bildschirmrand hinaus.
CSS Anchor Positioning ist ein weiteres neues Feature, das in den CSSWG-Meetings besprochen wurde und verspricht, solche Dinge viel, viel einfacher zu machen.
Einen Anker erstellen
Die Grundidee ist, dass wir zwei Elemente festlegen:
- eines, das als Anker fungiert, und
- eines, das ein an dieses Element gebundenes „Ziel“ (Target) ist.
Auf diese Weise haben wir eine deklarativere Methode, ein Element mit dem verankerten Element zu verknüpfen und relativ dazu zu positionieren.
Zuerst müssen wir unser Anker-Element mit einer neuen anchor-name-Eigenschaft erstellen.
Wir ändern unser Markup ein wenig:
<p>
<span class="anchor">Hover for a surprise</span>
<span class="tooltip">Surprise! I'm a tooltip</span>
</p>
Wir geben ihm einen eindeutigen dashed-indent als Wert (genau wie bei einer Custom Property).
.anchor {
anchor-name: --tooltip;
}
Dann verknüpfen wir den .tooltip mit dem .anchor unter Verwendung der Eigenschaft position-anchor bei entweder fixed oder absolute Positionierung.
.toolip {
position: fixed;
position-anchor: --tooltip;
}
Der .tooltip ist derzeit über dem .anchor positioniert, aber wir sollten ihn woandershin bewegen, um das zu verhindern. Der einfachste Weg, den .tooltip zu bewegen, ist die neue Eigenschaft inset-area. Stellen wir uns vor, der .anchor befindet sich in der Mitte eines 3×3-Rasters, und wir können den Tooltip innerhalb des Rasters positionieren, indem wir ihm eine Reihe und eine Spalte zuweisen.

Die Eigenschaft inset-area nimmt zwei Werte für den .tooltip in einer bestimmten Zeile und Spalte des Rasters entgegen. Sie arbeitet mit physischen Werten wie left, right, top und bottom, sowie logischen Werten abhängig vom Schreibmodus des Benutzers, wie start und end, zusätzlich zu einem gemeinsamen center-Wert. Sie akzeptiert auch Werte, die sich auf x- und y-Koordinaten beziehen, wie x-start und y-end. Alle diese Werttypen sind Möglichkeiten, einen Platz auf dem 3×3-Raster darzustellen.
Wenn wir beispielsweise möchten, dass der .tooltip relativ zur oberen rechten Kante des Ankers positioniert wird, können wir die Eigenschaft inset-area so festlegen:
.toolip {
/* physical values */
inset-area: top right;
/* logical values */
inset-area: start end;
/* mix-n-match values! */
inset-area: top end;
}
Wenn wir schließlich möchten, dass unser Tooltip über zwei Regionen des Rasters reicht, können wir ein span--Präfix verwenden. Beispielsweise platziert span-top den .tooltip in der oberen und mittleren Region des Rasters. Wenn wir stattdessen eine ganze Richtung überspannen wollen, können wir den Wert span-all verwenden.

Eines der Probleme mit unserem ankerlosen Beispiel ist, dass der Tooltip aus dem Bildschirm ragen kann. Wir können dies mit einer weiteren neuen Eigenschaft lösen, die position-try-options heißt, in Kombination mit einer neuen inset-area()-Funktion.
(Ja, es gibt die Eigenschaft inset-area und die Funktion inset-area(). Das ist etwas, das wir uns merken müssen!)
Die Eigenschaft position-try-options akzeptiert eine kommagetrennte Liste von Fallback-Positionen für den .tooltip, falls dieser aus dem Bildschirm ragt. Wir können eine Liste von inset-area()-Funktionen angeben, die jeweils dieselben Werte enthalten, die auch die Eigenschaft inset-area hätte. Jedes Mal, wenn der Tooltip den Bildschirm verlässt, wird die nächste deklarierte Position „ausprobiert“ (tried), und wenn diese Position ebenfalls zu einem Überlauf führt, wird die nächste probiert, und so weiter.
.toolip {
inset-area: top left;
position-try-options: inset-area(top), inset-area(top right);
}
Dies ist ein ziemlich wildes Konzept, das einige Zeit braucht, um es zu begreifen. CSSWG-Mitglied Miriam Suzanne hat sich zusammengesetzt, um Anchor Positioning mit James Stuckey Weber in einem Video zu diskutieren und auszuprobieren, das absolut sehenswert ist.
Geoff Graham hat Notizen zum Video gemacht, falls Sie eine kurze Zusammenfassung suchen.
Es gibt noch viele Aspekte von Anchor Positioning, die wir hier aus Gründen der Kürze nicht behandeln, insbesondere die neue anchor()-Funktion und die @try-position-At-Rule. Die anchor()-Funktion gibt die berechnete Position der Kante eines Ankers zurück, was mehr Kontrolle über die Inset-Eigenschaften eines Tooltips ermöglicht. Die @try-position-At-Rule dient dazu, benutzerdefinierte Positionen für die Eigenschaft position-try-options zu definieren.
Meine Vermutung ist, dass die Verwendung von inset-area für die große Mehrheit der Anwendungsfälle robust genug sein wird.
Die CSSWG ist eine Gemeinschaftsleistung
Zuvor sagte ich, dass dieser Artikel keine exakte Wiedergabe der Diskussionen bei den CSSWG-Treffen sein würde, sondern eher eine breite Darstellung neuer Spezifikationen für CSS, die aufgrund ihrer Neuheit zwangsläufig bei diesen Treffen zur Sprache kamen. Es gibt sogar einige Funktionen, für die wir in dieser Übersicht einfach keine Zeit hatten, sie zu prüfen, die aber immer noch diskutiert werden (hust, Masonry).
Eines ist sicher: Spezifikationen entstehen nicht im luftleeren Raum während ein oder zwei Treffen; es braucht die gemeinsame Anstrengung von Dutzenden großartiger Autoren, Entwickler und User-Agents, um das zum Leben zu erwecken, was wir täglich in unserer CSS-Arbeit verwenden – ganz zu schweigen von den Dingen, die wir in Zukunft nutzen werden.
Ich hatte auch die Gelegenheit, mit einigen großartigen Entwicklern der CSSWG zu sprechen, und ich fand es interessant, was ihre größten Erkenntnisse aus den Treffen waren. Man könnte erwarten, dass if() ganz oben auf ihren Listen steht, da dies in den sozialen Medien gehypt wird. Aber CSSWG-Mitglied Emilio Cobos erzählte mir zum Beispiel, dass die letter-spacing-Eigenschaft im Grunde fehlerhaft ist und es keine einfache Lösung gibt, um sie so zu korrigieren, dass sie mit der aktuellen Definition von letter-spacing in CSS und der Verwendung in Browsern vereinbar ist. Dazu gehört auch die Tatsache, dass das Umwandeln normaler Eigenschaften in Shorthand-Eigenschaften gefährlich für eine Codebasis sein kann.
Jedes winzige Detail, das wir vielleicht für trivial halten, wird sorgfältig analysiert – zum Wohle des Webs und aus Liebe dazu. Und wie ich bereits erwähnte, passiert dies nicht im luftleeren Raum. Wenn Sie sich für die Zukunft von CSS interessieren – sei es nur, um auf dem Laufenden zu bleiben oder um sich aktiv zu beteiligen –, dann ziehen Sie eine der folgenden Ressourcen in Betracht.
Anchor Positioning steht auf meiner Wunschliste, seit ich mein erstes Popup geschrieben habe. Ich freue mich riesig, dass es jetzt Teil von CSS ist.
Eine Sache, die ich allerdings immer noch zu verstehen versuche, ist, wie man einen kleinen Chevron oder Pfeil auf einem Pop-up in Reaktion auf die Position-Try-Optionen positioniert.
Man kann in der @position-try-Regel keine Custom Properties setzen, also gibt es scheinbar noch keinen Weg, dies zu tun.
Trotzdem unglaublich nützlich!
Hallo! Erstmal danke fürs Lesen. Ich wollte auch schon lange so etwas wie Anchor Positioning haben, daher ist es spannend zu sehen, wie die Browser die Unterstützung ziemlich schnell ausliefern.
Bezüglich deiner Frage: Wir werden im Almanac Einträge für jede Anchor-Positioning-Eigenschaft erstellen und ich werde versuchen, das bald nach Möglichkeit abzudecken. ;)
Ich habe hier ein CodePen-Beispiel: https://codepen.io/soluml/pen/wvZjVmW
Das Bewegen des Popups funktioniert perfekt, aber ich konnte keinen Weg finden, den Chevron zu positionieren.
Exzellenter Artikel, sehr gut geschrieben.