12k
All articles

Wann man CSS `if()` vs. Container Style Queries verwenden sollte

Vergleichen Sie CSS if() und Container Style Queries: wann Sie was nutzen, typische Syntaxfehler, Range-Syntax und Browser-Support 2026.

OpenReplay Team
OpenReplay Team
Wann man CSS `if()` vs. Container Style Queries verwenden sollte

Verwenden Sie die CSS-Funktion if(), wenn ein einzelnes Element seinen eigenen Wert inline bestimmen soll — für Theming-Tokens, Komponentenzustände oder eine responsive Eigenschaftsanpassung. Greifen Sie auf eine Container Style Query (@container style(...)) zurück, wenn der Stil eines übergeordneten Elements einen Satz von Regeln für mehrere untergeordnete Elemente steuern soll. Das mentale Modell in einem Satz: if() erzeugt einen elementlokalen bedingten Wert; eine Container Style Query etabliert einen Kontext und wendet bedingte Regelblöcke von einem übergeordneten Element auf seine Kindelemente an.

Beide sind bedingte CSS-Mechanismen, die benutzerdefinierte Eigenschaften auslesen, beide verwenden dasselbe style()-Query-Primitiv, und ihre Fähigkeiten überschneiden sich so weit, dass die Wahl des falschen Mechanismus zu unübersichtlichem Code führt. Dieser Artikel löst diese Überschneidung auf: was jeder Mechanismus leistet, der technische Unterschied, der die Wahl bestimmt, die zwei Syntax-Fallstricke, über die man stolpert (Semikolons und die Doppelpunkt-vs.-Gleichheitszeichen-Notation), die Range-Syntax, die nun in beiden verfügbar ist, eine Entscheidungstabelle nach Szenario, und wie man beide ausliefert, da die Browser-Unterstützung Mitte 2026 in drei Richtungen aufgeteilt ist.

Wichtigste Erkenntnisse

  • if() liest benutzerdefinierte Eigenschaften, die in der gleichen Regel am gleichen Element deklariert wurden, und gibt einen Wert zurück; @container style() schaut immer nur aufwärts durch die Kaskade und wendet ganze Regelblöcke auf Nachfahren an.
  • Innerhalb von if() trennen Semikolons (keine Kommas) die Bedingung-Wert-Paare, und else liefert den Fallback; wenn keine Bedingung zutrifft und kein else vorhanden ist, gibt die Funktion einen garantiert ungültigen Wert zurück, der zum Initialwert der Eigenschaft aufgelöst wird.
  • Innerhalb von style() führt die Doppelpunkt-Notation (style(--n: 3)) ein Token-/String-Matching ohne Mathematik durch, während die Vergleichsoperator-Notation (style(--n = 3)) beide Seiten numerisch parst und calc() zuerst auswertet.
  • Mitte 2026 unterscheiden sich die Unterstützungsszenarien: Grundlegende Container Style Queries sind in allen vier großen Engines verfügbar (Chrome 111+, Edge 111+, Safari 18+, Firefox 151+), während if() und die standardmäßig aktivierte Range-Syntax nur in Chromium verfügbar sind.
  • Da if() nur in Chromium verfügbar ist, benötigt jede if()-Deklaration entweder eine Fallback-Deklaration derselben Eigenschaft davor oder eine @supports-Absicherung.

Was jeder Mechanismus im Kern ist

Die if()-Funktion ist eine wertebene Bedingung, die man in jede Eigenschaft einfügt. Ihr Argument ist eine durch Semikolons getrennte Liste von Bedingung-Wert-Paaren, wobei jede Bedingung durch einen Doppelpunkt von ihrem Wert getrennt wird, und ein optionales else liefert den Standardwert:

.badge {
  color: if(
    style(--variant: danger): white;
    style(--variant: muted): #555;
    else: black;
  );
}

Jede Bedingung ist einer von drei Query-Typen:

  • style() testet eine benutzerdefinierte Eigenschaft am aktuellen Element;
  • media() führt eine inline Media Query aus;
  • supports() führt eine Feature Query aus.

Die MDN-Referenz dokumentiert alle drei mit derselben Semikolon-Grammatik — zum Beispiel schaltet flex-direction: if(media(orientation: landscape): row; else: column;) eine einzelne Eigenschaft basierend auf einem Media-Ergebnis um.

Eine Container Style Query ist eine @container-At-Regel, deren Bedingung aus einer oder mehreren style()-Notationen besteht, die die benutzerdefinierten Eigenschaften eines umgebenden Elements auslesen. Sie umschließt einen Regelblock, anstatt einen einzelnen Wert zu erzeugen:

.card { --status: active; }

@container style(--status: active) {
  .card-title { font-weight: 700; }
  .card-icon { opacity: 1; }
  .card-meta { color: green; }
}

Laut dem MDN-Leitfaden zu Container Queries ist jedes Element standardmäßig ein Style-Container — anders als bei Size Queries ist das Setzen eines container-type für Style Queries nicht erforderlich. Das beseitigt den wesentlichen Einrichtungsaufwand, den Entwickler von Container Queries erwarten.

Der grundlegende Unterschied, der die Wahl bestimmt

Der technische Unterschied liegt im Suchbereich. if() liest benutzerdefinierte Eigenschaften, die in der gleichen Regel am gleichen Element deklariert wurden, und ist in sich geschlossen, während @container style() immer nur aufwärts durch die Kaskade zu einem Vorfahren-Container schaut. MDN formuliert dies direkt: Die Verwendung einer Style Query innerhalb von if() ermöglicht es, ein Element danach auszurichten, ob eine benutzerdefinierte Eigenschaft auf ihm selbst gesetzt ist, anstatt Stile eines übergeordneten Elements zu prüfen. Beide werden ausdrücklich als komplementär und nicht als redundant beschrieben.

Dieser Unterschied im Suchbereich hat drei praktische Konsequenzen:

  1. Ausgabegranularität. if() setzt genau einen Wert. @container wendet einen ganzen Regelblock an — mehrere Deklarationen über mehrere Selektoren hinweg — wenn seine Bedingung zutrifft. Wie MDN es formuliert: Mit if()-Style-Queries können nur einzelne Eigenschaftswerte gesetzt werden, während @container-Queries bedingt ganze Regelsätze anwenden.

  2. Richtung. if() kann eine Eigenschaft lesen, die am Element selbst deklariert ist, das es stylt. @container kann nicht den eigenen Wert seines Elements lesen, um dieses Element zu stylen; es liest den Wert eines Vorfahren und stylt Nachfahren.

  3. Scoping. Nur Container Style Queries können nach container-name eingegrenzt werden. Benennt man einen Container, wertet die Query nur gegen diesen Container aus; wenn der benannte Container die abgefragte Eigenschaft nicht definiert, wird der Block schlicht nicht ausgeführt. if() hat keine entsprechende Scoping-Kontrolle — es löst immer gegen das Element auf, auf dem es sitzt.

Der entscheidende Faktor in der Überschneidungszone ist also: Wenn eine Eigenschaft an einem Element umgeschaltet werden soll, ist if() der direktere Weg. Wenn mehrere Nachfahren auf einen übergeordneten Wert reagieren müssen, drückt @container das mit einer einzigen Bedingung aus, anstatt if() bei jedem Kindelement zu wiederholen.

Die Syntax-Fallstricke, über die man stolpert

Semikolons, keine Kommas, trennen die Paare in if(). Das verwirrt jeden, der aus JavaScript kommt oder an kommagetrennte CSS-Funktionen wie rgb() gewöhnt ist. Die Grammatik lautet if(condition-1: value-1; condition-2: value-2; else: fallback), wobei das Semikolon nach dem letzten Paar optional ist. Außerdem darf kein Leerzeichen zwischen if und der öffnenden Klammer stehen, sonst ist die gesamte Deklaration ungültig. Und wenn keine Bedingung zutrifft und else fehlt, gibt if() einen garantiert ungültigen Wert zurück — in einem normalen Eigenschaftskontext wird dieser zum Initialwert der Eigenschaft aufgelöst, was selten gewünscht ist. else sollte daher immer angegeben werden.

Der Unterschied zwischen Doppelpunkt- und Gleichheitszeichen-Notation innerhalb von style() ist das subtile, hochrelevante Detail, das kaum jemand erklärt. Sowohl if() als auch Container Style Queries akzeptieren zwei Notationen mit grundlegend unterschiedlichem Verhalten, die nun auf MDN dokumentiert sind.

Die einfache (Doppelpunkt-)Notation führt ein Token-/String-Matching berechneter Werte durch und führt keine Mathematik aus. Die Range-(Operator-)Notation — mit =, <, <=, > oder >= — löst jede Seite auf, parst beide als numerischen Typ, wertet etwaiges calc() aus und vergleicht numerisch. Die Konsequenz, direkt aus MDNs eigenem Beispiel:

.box { --n: calc(6 / 2); }

/* FALSE: Der berechnete Wert von --n ist der String "calc(6/2)",
   der nicht dem Token "3" entspricht */
@container style(--n: 3) { /* … */ }

/* TRUE: Beide Seiten werden als <number> geparst, calc(6/2) ergibt 3,
   und 3 = 3 */
@container style(--n = 3) { /* … */ }

style(--n: 3) schlägt also bei --n: calc(6/2) fehl, während style(--n = 3) erfolgreich ist. Zwei weitere Regeln sind wichtig. Bei der einfachen Notation muss der Name der benutzerdefinierten Eigenschaft auf der linken Seite ohne var() stehen — style(var(--n): 3) ist ungültig —, während die Range-Notation auf beiden Seiten in beliebiger Reihenfolge einen Namen, var(), ein Literal oder calc() akzeptiert. Und äquivalente Werte (wie blue und #0000ff) stimmen unter der Doppelpunkt-Notation nur überein, wenn die Eigenschaft mit @property und einem syntax-Deskriptor registriert ist. Die Schlussfolgerung: Verwenden Sie die Doppelpunkt-Notation für Keyword-/String-Matching (style(--theme: dark)) und die Operator-Notation für numerische Vergleiche (style(--columns >= 3)).

Range-Syntax ist nun in beiden verfügbar

Die Range-Syntax erweitert beide Mechanismen über exaktes Matching hinaus auf numerische Vergleiche und bezieht Operanden aus benutzerdefinierten Eigenschaften, attr() oder Literalwerten. Laut den Chrome-142-Versionshinweisen löst ein Vergleich nur auf, wenn beide Seiten zum gleichen Datentyp auflösen, beschränkt auf sieben numerische Typen: <length>, <number>, <percentage>, <angle>, <time>, <frequency> und <resolution>. Die dreiwertige Intervallform funktioniert ebenfalls — @container style(0 < --n < 10) — wobei beide Vergleichsoperatoren in dieselbe Richtung zeigen müssen.

Die Range-Syntax ermöglicht elegante Muster wie ein Benachrichtigungs-Badge. Man liest einen Zähler aus einem Attribut aus und verzweigt nach Schwellenwerten:

@container style(--count > 99) {
  .badge::after { content: "99+"; }
}

Da die Range-Notation numerisch parst, ist style(--s = new) für ein Keyword wie new falsch, während style(--s: new) wahr ist — ein weiterer Grund, warum die Wahl der Notation entscheidend ist.

Welches Tool nach Szenario zu verwenden ist

SzenarioGreifen Sie zuWarum
Theming-Token → eine Eigenschaft (z. B. color aus --theme)if()Ein Element bestimmt seinen eigenen Wert inline
Komponentenzustand schaltet mehrere Kindstile um (aktiv/Fehler)@container style()Ein übergeordneter Wert steuert einen Regelblock über Nachfahren
Responsive Anpassung einer einzelnen Eigenschaftif() mit media()Lokalisierte Logik pro Eigenschaft; kein @media-Block erforderlich
Schwellenwerte für Benachrichtigungs-BadgesBeide, über Range-Syntax@container wenn Geschwister ebenfalls reagieren; if() wenn nur das Badge sich ändert
Kontrastbewusster Text auf einem themed übergeordneten Element@container style()Kindelemente lesen das Theme des übergeordneten Elements und werden gemeinsam neu gestylt
Feature-gesteuerter Wert (z. B. lch() mit Fallback)if() mit supports()Einzelner Werttausch bei Unterstützung
Mehreigenschaftiges Layout-Wechsel an einem Breakpoint@media (keines von beiden)Beide sind das falsche Werkzeug für große Layout-Änderungen

Die Faustregel: Ein einzelner bedingter Wert ist ein Fall für if(); ein bedingter Kontext, der einen Teilbaum neu stylt, ist ein Fall für eine Container Style Query.

Auslieferung im Jahr 2026

Die Browser-Unterstützung teilt sich in drei Bereiche auf, und die alte Formulierung „bedingtes CSS ist nur in Chromium verfügbar” ist nicht mehr zutreffend. Browser-Unterstützung Stand Juni 2026:

FeatureChrome / EdgeSafariFirefox
Container Style Queries (benutzerdefinierte Eigenschaften, einfache Syntax)111+18+151+
if()-Funktion137+Nicht verfügbarNicht verfügbar
Range-Syntax in style() / if()142+ (standardmäßig aktiviert)Nicht verfügbar151, hinter layout.css.attr.enabled

Grundlegende Container Style Queries sind nun wirklich engine-übergreifend verfügbar. Sie wurden in Chrome und Edge 111 eingeführt, erreichten WebKit in Safari 18.0 und kamen in Firefox 151, veröffentlicht am 19. Mai 2026, das @container-style()-Query-Unterstützung basierend auf benutzerdefinierten Eigenschaften eines Containers hinzufügte. Die if()-Funktion hingegen ist weiterhin nur in Chromium verfügbar — MDN kennzeichnet sie als experimentell mit eingeschränkter Verfügbarkeit — und die Range-Syntax ist standardmäßig nur in Chromium aktiviert. Firefox 151 liefert @container-style()-Range-Syntax aus, jedoch standardmäßig deaktiviert, hinter der Einstellung layout.css.attr.enabled.

Die praktische Schlussfolgerung: if() degradiert nicht gracefully, daher sollte zuerst eine Standarddeklaration geschrieben werden und unterstützende Browser diese überschreiben lassen, oder die Regel in eine @supports-Absicherung eingebettet werden. Ein Muster deckt beide Mechanismen ab:

/* Fallback zuerst — jeder Browser wendet dies an */
.card-title { font-weight: 400; }

/* Progressive Enhancement: Nur style-query-fähige Engines wenden dies an */
@supports (container-type: normal) {
  @container style(--status: active) {
    .card-title { font-weight: 700; }
  }
}

/* if(): Statischer Wert zuerst, dann die bedingte Überschreibung */
.badge { padding: 0.25em; }
.badge { padding: if(style(--size: lg): 0.5em; else: 0.25em); }

Da if() und standardmäßig aktivierte Range-Syntax in Firefox und Safari — Browser, die ein Chrome-fokussierter Entwickler während der Entwicklung selten öffnet — auf ihren Fallback-Pfad zurückfallen, ist browserübergreifendes Session-Replay eine nützliche Technik, um den Fallback-Zweig tatsächlich in einem echten Browser eines Nutzers zu beobachten, anstatt anzunehmen, dass er korrekt aussieht. Für die tiefergehenden calc()- und Verschachtelungsmuster innerhalb von if() geht LogRockets entscheidungsorientierter Walkthrough weiter, als hier Platz ist.

Wählen Sie nach Absicht, nicht nach Neuheit: Ein bedingter Wert an einem Element ist ein Fall für if(); ein bedingter Kontext, der einen Teilbaum von einem übergeordneten Element aus neu stylt, ist ein Fall für eine Container Style Query. Liefern Sie beides heute hinter einem Fallback aus, überprüfen Sie die Unterstützungsmatrix erneut, bevor Sie if() in der Produktion einsetzen, und beide werden zunehmend den Bereich des bedingten CSS abdecken, der früher benutzerdefinierte Eigenschafts-Hacks und JavaScript erforderte.

FAQs

Können Container Style Queries die eigene benutzerdefinierte Eigenschaft desselben Elements lesen, wie es `if()` kann?

Nein. Eine Container Style Query schaut immer aufwärts durch die Kaskade zu einem Vorfahren-Container und wendet ihre Regeln auf Nachfahren an, sodass sie keine benutzerdefinierte Eigenschaft des Elements lesen kann, das sie stylen würde. Die `if()`-Funktion ist das Gegenteil: Sie liest benutzerdefinierte Eigenschaften, die in derselben Regel am selben Element deklariert wurden, und löst einen Wert inline auf. Wenn ein Element auf seine eigene Eigenschaft verzweigen soll, verwenden Sie `if()`; wenn der Wert eines übergeordneten Elements seine Kindelemente neu stylen soll, verwenden Sie eine Container Style Query.

Erfordern Container Style Queries das Setzen eines `container-type`, wie es Size Queries tun?

Nein. Jedes Element ist standardmäßig ein Style-Container, sodass Style Queries auf benutzerdefinierten Eigenschaften ohne Deklaration von `container-type` funktionieren. Dies unterscheidet sich von Container Size Queries, die `container-type` (z. B. `inline-size`) am abgefragten Vorfahren erfordern, bevor eine Size-Bedingung aufgelöst werden kann. Dies ist im MDN-Leitfaden zu Container Queries dokumentiert und beseitigt den wesentlichen Einrichtungsschritt, den Entwickler beim ersten Einsatz der `@container`-At-Regel erwarten.

Warum trifft meine Style Query mit `calc()` nie zu?

Weil die einfache Doppelpunkt-Notation Token- und String-Matching ohne Mathematik durchführt. Eine Eigenschaft, die auf `calc(6 / 2)` gesetzt ist, wird zum String 'calc(6/2)' berechnet, der nie dem Token 3 entspricht, sodass `style(--n: 3)` false zurückgibt. Um numerisch zu vergleichen, verwenden Sie die Vergleichsoperator-Notation `style(--n = 3)`, die jede Seite auflöst, `calc()` auswertet, beide als numerischen Typ parst und numerisch vergleicht, sodass true zurückgegeben wird. Verwenden Sie die Doppelpunkt-Form für Keyword-Matching und die Operator-Form für numerische Vergleiche.

Degradiert `if()` gracefully in Safari und Firefox?

Nein. Stand Mitte 2026 ist `if()` nur in Chromium-Browsern verfügbar (Chrome und Edge 137+), sodass Safari und Firefox jede Deklaration, die es enthält, ignorieren und auf den zuvor gültigen Wert zurückfallen. Schreiben Sie zuerst eine statische Standarddeklaration und lassen Sie unterstützende Browser diese überschreiben, oder umschließen Sie die bedingte Regel mit einer `@supports`-Absicherung. Grundlegende Container Style Queries sind engine-übergreifend sicherer und werden in Chrome 111+, Edge 111+, Safari 18+ und Firefox 151+ unterstützt, aber die standardmäßig aktivierte Range-Syntax bleibt weiterhin nur in Chromium verfügbar.

Open-source session replay

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.