Rolf B: @when das W3C aufSASSig wird - CSS Conditionals Level 5 und die Kompatibilität

Die CSS Conditionals 5 Spezifikation entwickelt sich. Aber sie haben ein Problem: SASS

Wer SASS kennt, weiß es: Man kann – auf dem Server, zur Generierungszeit – Bedingungen formulieren und damit beispielsweise steuern, welche CSS-Variante ein Mixin erzeugt. Das Schlüsselwort, das SASS dafür verwendet, heißt @if – und damit wildert es im Wald der generellen Syntax für @-Regeln, die CSS im Browser verwendet.

Das war lange unkritisch, aber das W3C entwickelt seit ein paar Jahren an der Stufe 5 von CSS-Bedingungen (CSS Conditionals Level 5). Die bisherigen Stufen brachten uns @media-Queries für Medientypen und Medienfeatures, sowie @supports-Abfragen für Eigenschaften und Selektoren.

Mit Stufe 5 wird @supports um Abfragen für Font-Technologien und Font-Formate erweitert. Die zugehörige Syntax lautet

   @supports font-tech(name) { ... }
   @supports font-format(format) { ... }

Als Format können diejenigen Formate angegeben werden, die in der format()-Angabe der src-Eigenschaft einer @font-face Definition zulässig sind, also beispielsweise woff2, truetype oder eot.

Font-Technologien sind etwas, was in Abschnitt 11 der CSS Fonts 4 Spezifikation beschrieben wird. Wenn Sie Spezialfonts verwenden wollen, die besondere Technologien verwenden, dann sollte sich bei dem jeweiligen Font ein Hinweis auf diese Technologien finden. Wenn nicht, dann sind diese Abfragen für Sie ohne Belang.

Und was hat es nun mit SASS auf sich?

Die dritte Neuerung, die uns CSS Conditionals 5 bringen wird, ist eine Zusammenführung von @media- und @supports-Abfragen in eine generelle Abfragesyntax, die auch Abfrageketten und einen Defaultzweig ermöglicht. Also das, was Programmierer schon längst als

if (bedingung)
   ...
else if (bedingung)
   ...
else
   ...

kennen.

Und hier liegt die Crux: Die Spezifikation verwendet eine @-Regel Syntax, aber @if ist bereits von SASS reserviert worden. Würde natives CSS nun ein @if einführen, so wäre entweder SASS gezwungen, dem Präprozessor genug Intelligenz einzuhauchen, um ein SASS-@if von einem CSS-nativen @if zu unterscheiden – oder alle SASS-Quellen müssten von @if auf ein @-sass-if oder etwas ähnliches umsteigen.

Weil SASS eine gewaltige Verbreitung hat, wollte man das vermeiden. Die Spezifikation verwendet statt @if deshalb eine Syntax mit @when:

@when bedingung {
   ...
}
@else bedingung {
...
}
@else {            /* Default-Fall */
   ...
}

Als Bedingung kommt eine Syntax zum Einsatz, wie sie für @supports eingeführt wurde. Für die bisherigen Abfragen auf Medienfeatures und unterstützte Eigenschaften werden die Pseudofunktionen media() und supports() eingeführt. selector(), font-format() und font-tech() wird von @supports übernommen:

@when media(width > 50em) 
@when supports(background-music:url(foo.wav))
@when selector( body:has(:passive) )
@when font-format(woff2)
@when font-tech(color-COLRv0)

Die Abfragen auf background-music und :passive sollten in aktuellen Browsern natürlich fehlschlagen…

Das lässt sich auch mit AND und OR kombinieren, die Spec enthält dieses Beispiel:

@when media(width >= 400px) and media(pointer: fine) and supports(display: flex) {
  /* A */
}
@else supports(caret-color: pink) and supports(background: double-rainbow()) {
  /* B */
}
@else {
  /* C */
}

Das ist ziemlich großartig, und erspart uns umständliche Doppelabfragen auf width > 50em und width <= 50em. Her damit, sag ich!

Womit man aber nicht gerechnet hatte, war der Aufschrei der Community. Wie man denn auf die Idee käme, das so naheliegende @if zu verwerfen, und einen Kniefall vor einem dahergelaufenen Toolfuzzi zu machen? „Tools kommen und gehen, Standards sind für die Ewigkeit“, wurde angeführt, also habe sich doch SASS gefälligst zu bewegen und der Spec Platz zu machen. Und weil die Änderung nicht die Benutzer, sondern die Autoren betrifft, ist das doch alles kein Thema. Schnell mal den Replace auf die Codebasis, SASS updaten, und gut ist. Höre ich da ein leises Mimimi? Pah! Nun gut, Lea Verou hat es freundlicher formuliert.

Das ignoriert natürlich den Umstand, dass SASS nicht irgendein zusammengefrickeltes Tool mit 13 Anwendern ist. Es ist 4 Jahre älter ist als der erste CSS-3 Draft, der @media-Featurequeries und eine @supports-Regel einführte. Bei SASS kam damals niemand auf die Idee, dass 2021 ein erster Working Draft für CSS-Bedingungen mit @when (oder @if oder @on oder @case oder was auch immer) veröffentlicht werden würde. Und es ignoriert den Umstand, dass der größte Teil professionell erstellter Webseiten CSS Präprozessoren wie SASS verwendet. Das Mimimi wäre also eher ein Hurrikan.

Gut, die Diskussion zu @if vs @when ist etwa 5 Jahre älter, wie Tab Atkins in einem der Zank-Threads zu diesem Thema schrieb, aber dennoch kann man von SASS nicht erwarten, so weit in die Zukunft zu schauen. Viellecht hätte man erwarten können, dass SASS nicht den "Namensraum" der @-Regeln in Beschlag nimmt und %-Regeln statt @ Regeln verwendet. Die Diskussionen dazu wirken allerdings teilweise so, als ginge es vor allem ums Rechthaben, und nicht darum, eine praktische Lösung zu finden.

Werden wir nun als Partner für @else ein @when bekommen? Oder doch ein @if? Werden SASS-User einen globalen Search&Replace auf ihre Codebasis machen müssen, um @if durch @-if zu ersetzen? Oder gar eine Option, um @if durch %if zu ersetzen? In den Diskussions-Threads ist es stiller geworden, und bislang steht in der CSS Conditionals 5 Spec immer noch ein @when.

Aber bisher hat es auch noch kein Browserhersteller unternommen, mit der Implementierung zu beginnen. Bei Chromium, Mozilla und Webkit existieren Implementierungstickets, aber bei keinem steht etwas von "Arbeit begonnen". Wir können uns nur wünschen, dass der Streit bald geklärt wird und @else endlich erfährt, wozu sie die Alternative liefern darf.

Quellen

  1. Nur ein flüchtiger Gedanke, der sich bei den if/else if/else if/ … eingestellt hat: switch/case!

    Das wäre, würde ich meinen, eine druchaus praktikable Alternative zum if. Und wie in swift behandelt, also ohne fall though … könnte das doch auch, vielleicht sogar besser, passen⁈

    Immerhin: wie sieht es denn beispielsweise bei den Querries aus? Wie schnell überlappen sich da Anforderungen und bestimmen dann, vmtl. ob ihrer Reihenfolge, ob nun die eine oder andere gewinnt? Mit einem switch/case-Konstrukt (incl. default-Zwang wie in swift?) könnte da was in ähnlicher Weise zusammengefaßt werden, wie die CSS-Regeln mit Nesting: einerseits kann es damit übersichtlicher werden. Andererseits findet man beim Zusammenfassen von bestehendem CSS in Richtung Nesting auch schnell mal die eine oder andre Leiche.

    1. Hallo nix,

      die Spezifität von CSS Regeln wird durch Queries jeglicher Art nicht beeinflusst.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Aber man wird doch, von technischen Aspekten mal abgesehen, noch was für die Menschen tun dürfen (die sich das ansehen oder es gar gestalten müssen)?

    2. Ohne die Diskussion zu kennen, würde ich sagen, dass @if ohnehin nicht das Optimum ist. if ist eine binäre Entscheidung, man benötigt also zur Abbildung nicht-binärer Konditionen weitere Hilfmittel (in Form von Operatoren wie AND, OR, NOT und/oder binäre Entscheidungsbäume. Warum also nicht gleich die "parallelen" Konstrukte verwenden, bei denen beliebig viele nebeneinander gleichberechtigt vorkommende Möglichkeiten erlaubt sind?

      Und falls @when nicht einfach als Ersatz für @if gedacht ist (also parallel und nicht bloß binär), dann hielte ich das für begrüßenswert. Wenn man Programmtexte mit if-Entscheidungsbäumen ausformuliert, die eigentlich parallele Strukturen darstellen, sieht das schon rein optisch verdächtig aus.

      Die Wahl des "when" ist eigentlich kein schlechter Vorschlag. In SQL beispielsweise werden genau damit auch die in anderen Sprachen verwendeten switch/case-Konstrukte deklariert:

      CASE ausdruck
      WHEN ausdruck1 THEN ergebnis1
      WHEN ausdruck2 THEN ergebnis2
      ELSE default_ergebnis
      END
      

      Das aber ist das, was die Spezifikation vorschlägt (wobei CASE und END aufgrund der Klammerung entbehrlich sind und die defaults optinal bleiben können). Ein @when ersetzt also streng genommen nicht @if, sondern ist bereits ein Ersatz für switch/case, die ihrerseits eine Erweiterung von if sind.

      Problematischer sehe ich da eher die Entscheidung, Programmlogik in CSS einzubauen. Aber wenn (was aus praktischer Sicht sehr begüßenswert ist!) das kommt, dann gerne gleich in dieser erweiterten Form.

      SASS (und somit auch die älteren Codes) würde das zu nichts zwingen. Allerdings letztlich in gewisser Weise überflüssig machen, wenn man die Entscheidungen über den Transport des CSS dann auf den Client überträgt und nicht beim Server belässt.

      1. Und so ganz nebenher ist ein

        switch {
          case a: { … }
          case b: {
            switch {
              case e: { … }
              case f: { … }
            }
          }
          case c: { … }
        }
        

        deutlich übersichtlicher als

        if a { … }
        else if b {
          if e { … }
          else { … }
        }
        else if c { … }
        

        Und wie schnell verschachtelte if/else-if-Konstrukte daneben gehen, lernt man ja schon mit C normalerweise ziemlich schnell.