Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-conditional-4] Rename @when to @if #6684

Open
LeaVerou opened this issue Sep 24, 2021 · 114 comments
Open

[css-conditional-4] Rename @when to @if #6684

LeaVerou opened this issue Sep 24, 2021 · 114 comments

Comments

@LeaVerou
Copy link
Member

LeaVerou commented Sep 24, 2021

The reasoning for using @when over @if is that @if clashes with Sass, a widely used CSS preprocessor. To my knowledge, no other reasoning exists for this decision.

However, there is a lot of pushback against this decision (and general philosophy) in #112. I have gathered quotes about this below.

Some arguments against @if have been posted by Sass maintainers in w3ctag/design-principles#335 which has received a lot of attention from the Sass community through this tweet.

My take:

  1. Third party tools can change far more easily than web standards, which are supposed to last for decades. We don't want to be stuck with a weird @when keyword decades after Sass is not used any more, making for yet another funny story about "why CSS is weird". The whole point of preprocessors should be to prototype features for CSS' future. Designing CSS around Sass is going the wrong way up the proper chain of dependency. It's like Babel forcing TC39 to not change a proposal because too many people transpile it a certain way.
  2. There are far more CSS users than users of any particular preprocessor, so their needs should be weighed significantly more heavily. Not infinitely, but very significantly.
  3. There is precedent for using if for conditionals in almost every language that includes conditional statements (and not just imperative languages as has been erroneously mentioned). For example, spreadsheets and all flavors of SQL (SQL Server, MySQL, even SQLite), Lisp, Haskell, Erlang, XSLT, all of which are considered declarative.
  4. Many ways for Sass to deal with this change have been mentioned in [mediaqueries][css-conditional] else #112. There could be a switch, users can use an old version of Sass until they are ready to migrate, and so on. Ways for Sass to avoid clashing with CSS have been mentioned too. CSS has had an extension mechanism for over a decade, it's called vendor prefixes. What happens if in the future we want to add a looping construct to CSS as well? @each, @for, @while are all taken. How much do we contort CSS to avoid clashing with preprocessors?
  5. CSS has already made syntactic decisions to avoid clashing with Sass, namely square brackets over parentheses in grid properties. However, those were two alternatives that more or less had the same usability, so a decision to avoid clashing with Sass was more justifiable. Here, @when has serious usability problems:
    • It goes against conditional naming in almost every structured language.
    • In natural language, "when" is used for something that hasn't happened yet, whereas if is more synchronous.
    • There are thoughts to add inline conditionals as well (e.g. [css-values]: Express conditional values in a more terse way  #5009 ). Are we going to name those functions when() as well? Are we going to name them something unrelated, like cond()? Do note that these also clash with Sass if called if()... link
  6. Note that the even the CSS WG resolution to adopt this proposal said "if/else". This is how entrenched this naming is! If @when is adopted, this will make for decades of users mistyping CSS conditionals.
    Quotes from [mediaqueries][css-conditional] else #112:

@Marat-Tanalin (1):

Fwiw, in the past, a SASS developer said at www-style that existing features of SASS should not be considered as limitations for new CSS features in any way:

if a potential new CSS feature is conflicting with an existing SASS feature, then the latter could just be changed.

@Marat-Tanalin (2):

Yeah, Sass usage does not trump CSS. But there's also no reason to be hostile to the developer community when we can easily avoid such.

Replacing the clear straightforward keyword widely used in almost all languages with an invented more-or-less similar one is actually probably not that easy.

At the same time, SASS (as well as any other preprocessor) could really easily rename its @if or just transparently convert something like @css-if or @native-if to native CSS @if. That’s not a CSS problem at all.

CSSWG decisions should probably not be based on the goal of avoiding preprocessor conflicts. CSS is a much more fundamental thing that require carefully weighed decisions reasonable and usable in the long term. Preprocessors can be changed at any time, CSS cannot at all.

@upsuper:

I'd prefer @if... not very strongly, though.

I agree with @Marat-Tanalin that we should not pick a weird syntax just to avoid conflicting with a preprocessor, and preprocessors can always work around that easily, either via a breaking change stated in the release note or introducing a new keyword.

I can imagine that if we choose @when and @else-when, more developers would tend to critize that CSSWG is making their life harder via adding some syntax different than what they are familiar with, rather than appreciating the work of avoiding the imaginary breakage.

I think the criteria is, is there more web developers use SASS's @if than those who do not use SASS's @if (or do not use SASS at all) but familiar with the general if-else structure? What's the percentage?

@bradkemper:

I strongly prefer @if, @else, and @else-if. It would be clear and obvious for most authors, and SASS could easily adapt.

@leaverou:

I'd like to express my strong agreement with @upsuper, @Marat-Tanalin and @bradkemper above in favor of @if over @when.

  1. Consistency with every other language authors may have used
  2. As has been repeatedly mentioned, we should not be designing CSS, a language that needs to last decades and for which the burden of changes is incredibly high, based on conflicts with a preprocessor that happens to be in use today (and is already giving way to others, e.g. PostCSS). Preprocessors can adapt far more easily than CSS, and any third-party project ultimately has far fewer users than CSS. Many solutions for Sass have been suggested in this very thread.
  3. Preprocessors are not executed on every page load, so it's far easier for Sass authors to migrate to a new syntax at their own time. This is not like the issue TC39 faced with array.contains() at all.

Note: @if is used quite heavily: about 63% of Sass stylesheets use it. But even if it was used in 100% of them we should not design CSS around Sass.

@svgeesus:

Adding my agreement to call this @if not @when.

I recall that the Sass maintainers have explicitly stated that CSS should not avoid a good syntax just because Sass uses it; they are very willing to change so that CSS can get better.

@iain-davis
Copy link

iain-davis commented Sep 24, 2021

My observation is that @when may better choice than @if but that observation is lightly held. Given the nature of CSS and its purpose, @when is language that is closer to CSS' role. That is, "when this condition exists apply this style" communicates intent far more clearly than "if this condition apply this style"

I think it is important to recognize that CSS is a not a general purpose language. It is a domain-specific language. An essential part of a domain specific language is keeping the domain of the language in mind when making keyword and syntax decisions.

I'd also argue that when a language uses a different-from-the-familiar keyword, that can signal to a engineer that the keyword may not operate with the same sense or nuance that it does in another language. This could be particularly valuable in a language like CSS, where its nature is very different from general purpose languages.

The reasoning for using @when over @if is that @if clashes with Sass, a widely used CSS preprocessor. No other reasoning exists for this decision.

That may be the reasoning of the folks that selected @when, but that certainly wouldn't be my reasoning. So there are definitely is other reasoning for making the decision. I've no special attachment to SASS, I regard it just as ephemeral is any other technology or tool. There's definitely some impacts to weigh there, SASS is widely used, and identifying a responsible migration path would be essential for this change. But that's not the only reason

We don't want to be stuck with a weird @when keyword decades after Sass is not used any more, making for yet another funny story about "why CSS is weird".

I'd say most languages have such artifacts -- where the needs of the community of the time required the language to have a given feature. It's the reality of working on something while it is in use. Compromises have to be made to maintain compatibility with the users of a tool/language/technology.

And I'd say it's misleading to call using @when as a reason to call CSS weird. Again, CSS is not a general purpose language. It has needs that general purpose languages do not, so naturally it will differ from general purpose languages. That's the whole point of creating a domain specific language.

There are far more CSS users than users of any particular preprocessor, so their needs should be weighed significantly more heavily. Not infinitely, but very significantly.

This is a valid claim, as far as it goes. However, it focuses on the "quantity of those affected" without accounting for the "degree of impact". The impact of using @when over @if is relatively minimal, since the people affected by are highly intelligent and capable people. They can handle knowing that the conditional CSS syntax differs from other languages. However, for the community of SASS users, the impact may be significant. That'd depend entirely on what kind of backwards compatibility could be built by SASS.

There is precedent for using if for conditionals in almost every language

Just because it was done before doesn't make it the best thing in every scenario or language. It may not have even been the best thing at the time, just happened to be what someone thought of. Hopper's comment on this fallacy is probably the best: "The most dangerous phrase in the language is, ‘We’ve always done it this way.’"

I'm also curious what the actual statistics are around the 'if' keyword, and the connections between those languages that use it. I suspect we'll find a common set of ancestors (or ancestor) there. :)

What happens if in the future we want to add...

That's the future's problem. One can "what if" any idea into oblivion or stagnation.

In natural language, "when" is used for something that hasn't happened yet, whereas if is more synchronous.

Is CSS synchronous? I'd say it is more existential. It either is applied or is not. There's not, in some senses, a sequence to CSS.

In natural language, when does have "when this becomes true, ...". That also applies to if -- "if this becomes true, ...".

That it is not its only nuance. If we were talking tenses, it can also apply to "present perfect" in addition to the "future" tense you're referring to. For instance, the sentence "when I read, I wear funny hats" both captures past, present, and future conditions. And only future because we're assuming my past and present behavior is predictive of future behavior.

That nuance of when applies to CSS quite well. "When my page is 900px wide, all text will be green" is a similar nuance as "when I read, I wear funny hats".

If @when is adopted, this will make for decades of users mistyping CSS conditionals.

We still type???? ;) My guess it'll be typed once or twice, predictive text generated hundreds of times, and cut-and-pasted thousands of times. Again, CSS is its own domain. I think the context shift is sufficient to flip the switch in the brain from @if to @when.

The arguments for and against don't feel compelling to me in either direction. The concerns about backward compatibility are valid but there are also times when one has to let an API change to accommodate future changes. Following common patterns has value but there are times when we have to adopt a new pattern -- otherwise we're stuck doing the same thing over and over, forever.

Natural language and conveying intent is complicated to evaluate -- natural languages are richly varied and highly complex, while a programming language is, by design, specific (to their domain of machine instructions) and unambiguous. And domain languages are, by design, even more specific to their domain, Making nuanced decisions about keywords of a language on that basis is difficult and fraught with cultural bias. :)

@mikemai2awesome
Copy link

The reasoning for using @when over @if is that @if clashes with Sass, a widely used CSS preprocessor. No other reasoning exists for this decision.

Since this thread leads with that, I'll re-iterate my thoughts from elsewhere:

From a standards and conventions point of view, I think that (choose @when over @if) sets a bad precedent. It will lead to other makers of 3rd party tools to think "well, if we are popular enough, the CSS spec will just design around us". I know Sass isn't just an ordinary 3rd party tool, so it's even more important for them to lead by example. Breaking changes are hard to deal with, but whoever chooses to use a third party tool has the responsibility to adapt changes.

I know some have expressed that @when is actually a better choice because it describes what it does, but I am failing to see any examples making a convincing case. Please share some actual code examples (intended usage) for those who don't have the context.

@simonbuerger
Copy link

simonbuerger commented Sep 25, 2021

CSS should actively steer clear of familiar control flow structure syntax because it is not an imperative language.

"If this is true do this thing" vs "When this is true use these rules"

So a vote here from me for @when over @if

@bradkemper
Copy link
Contributor

bradkemper commented Sep 26, 2021

That nuance of when applies to CSS quite well. "When my page is 900px wide, all text will be green" is a similar nuance as "when I read, I wear funny hats".

There are many ways to misunderstand any programming structure once we start fleshing it out into natural language according to our own preconceived notions. You are adding "will be", but it could just as easily be (theoretically) understood as "When my page was 900px wide, all text should have been green". I mean, unlikely that anyone would actually think that, but also unlikely that they would have difficulty understanding what @ifmeans. With more natural language would be "If my page is ever 900px wide, all text at that time should be green".

@LeaVerou
Copy link
Member Author

LeaVerou commented Sep 26, 2021

CSS should actively steer clear of familiar control flow structure syntax because it is not an imperative language.

"If this is true do this thing" vs "When this is true use these rules"

So a vote here from me for @when over @if

Control flow is not a characteristic of imperative languages. Many (possibly most) declarative languages have control flow structures, and as I mentioned in my original post, tend to call conditionals if:

There is precedent for using if for conditionals in almost every language that includes conditional statements (and not just imperative languages as has been erroneously mentioned). For example, spreadsheets and all flavors of SQL (SQL Server, MySQL, even SQLite), Lisp, Haskell, Erlang, XSLT, all of which are considered declarative.

@vrugtehagel
Copy link

vrugtehagel commented Sep 28, 2021

I'm leaning towards @if. I'll explain why.

First of all, I want to talk about the difference in meaning between the words "if" and "when". I'm not a native English speaker, so I may get nuances wrong, but I think people generally agree that "when" implies some timescale, a moment in the future when a certain condition will inevitably happen. I can say "I don't know when I'll leave the house" and "I don't know if I'd leave the house" and they'd mean different things; the first implies I will leave the house, I'm just unsure at what point in time. The second implies I'm not sure whether I'll leave the house altogether, regardless of time. For this CSS condition, I don't believe it would make sense to use @when; the condition is not guaranteed to ever happen, and is not bound to time in any way. @if seems a much better choice in that aspect.

As for the clash with SASS, that's the bigger issue. I think most people want to call this rule @if, otherwise we wouldn't be having this discussion. So ultimately, the question is "should we care about breaking this third-party tool when speccing CSS". The way I see it, it's a bit up to interpretation of what the "environment" really encompasses (specifically, if SASS is considered part of the ecosystem or not). As a person who doesn't particularly value SASS, I could easily say "SASS should suffer the consequences" but it's not quite that simple. Let me go into this a little deeper.

First, I want to address arguments along the lines of "we're bending some JavaScript features in order to not break the web, why can't we do the same for CSS". Yes, we did have to rename some things for JavaScript just because the initially proposed name would break things. In my opinion, this is a bit different. Let's say (hypothetically) I built a site 5 years ago using MooTools (specifically using Array.prototype.flatten) as well as SASS (specifically using @if). I've long forgotten about this site, but it's still up and running and let's assume that people use it often enough to care about it breaking. If JavaScript introduced Array.prototype.flatten, my site would break without my knowledge, even though I didn't touch it. This negatively affects users. If CSS introduced @if, then... well, nothing. I already built my CSS 5 years ago, and my CSS (the output) didn't use @if, so that's all good. My SCSS build may fail, but that's irrelevant; my site didn't break for its users. Basically, the difference between breaking something for a JavaScript library versus breaking a CSS preprocessor is that the latter doesn't directly impact users of the web, while the first may break many unmaintained sites when released in browsers.

Now, let's say I wrote a preprocessor that would clash with a new CSS feature, just like SCSS. Would I expect CSS to go out of its way to avoid doing so? No, definitely not, as the amount of users affected by my preprocessor breaking would likely be insignificant. Obviously, the difference with SCSS is that it has an absolutely massive user base. Many people would be negatively impacted by a change that would cause their SCSS to break, cause them to have to migrate or stick to an older SCSS version that prevents them from getting other juicy updates to SCSS. The question is whether or not we should take this into consideration. Is SCSS "part of the web ecosystem", and we therefore have to protect them from this type of inconvenience, or is SCSS just a third party tool that shouldn't be taken into consideration whatsoever when making decisions about CSS? This is (the way I see it, anyway) at the heart of this discussion, and it's a difficult question.

I wholeheartedly believe in making the web an amazing place for everyone, and breaking SCSS @if would, to say it bluntly, suck, for a lot of developers. On the other hand, I'm a bit of a purist, so I'd prefer not to make compromises on language features based on a tool that developers use. Additionally, SCSS is, in a way, more "temporary" and easier to change than CSS itself, so there could be a time where SCSS slowly dies out (perhaps because CSS itself became feature-rich enough for most developers) and by that time we're stuck with a less intuitive @when rather than just @if.

In the end, if we can get away with introducing @if, I'd say we should. We had to make compromises for JavaScript because we had no choice, but here, we do have a choice. If we'd introduce @if in browsers now, no site would be affected (not many, anyway, though this is just an assumption), but instead it'll cause a a major inconvenience to a lot of SCSS developers that they'll have to get through in order to create a "better future" for all future developers.

@simonbuerger
Copy link

@vrugtehagel @LeaVerou well reasoned. @vrugtehagel you made me think though, wouldn't @where have actually been a better alternative to @when, linguistically speaking? Come to think of it SQL actually has where, if and when which all deal with conditionals in different situations 😬

@Marat-Tanalin
Copy link

@vrugtehagel

If JavaScript introduced Array.prototype.flatten, my site would break without my knowledge, even though I didn't touch it. This negatively affects users. If CSS introduced @if, then... well, nothing. I already built my CSS 5 years ago, and my CSS (the output) didn't use @if, so that's all good. My SCSS build may fail, but that's irrelevant; my site didn't break for its users. Basically, the difference between breaking something for a JavaScript library versus breaking a CSS preprocessor is that the latter doesn't directly impact users of the web, while the first may break many unmaintained sites when released in browsers.

👍

SCSS is, in a way, more "temporary" and easier to change than CSS itself, so there could be a time where SCSS slowly dies out (perhaps because CSS itself became feature-rich enough for most developers) and by that time we're stuck with a less intuitive @when rather than just @if.

👍

@ianthedev
Copy link

ianthedev commented Oct 5, 2021

A comment in another thread mentioned:

If you don't want to choose @when just because it'll break a 3rd-party tool, choose @when because it makes more sense in a declarative (stylesheet) setting.

Please take a look at the following code:

@when supports(display: grid) {

} @else {

}

The @when in the code above literally implies that a browser only supports grid at a certain time and not at other times, and that makes no sense. Using @if makes much more sense in such cases.

@mikemai2awesome
Copy link

Maybe it's because English is not my first language, but I am failing to see the above argument. Why @if is worse than @when in such case? "If browser supports grid, do this; else do that." What is wrong with such sentence? @ianthedev

@ianthedev
Copy link

@mikemai2awesome Sorry for not being clear. I meant to say @if is better than @when in such cases. I just updated my comment.

@SebastianZ
Copy link
Contributor

I learned at school (as a non-native English speaker) that "when" can be both "if" and "as soon as".
E.g. "When I have time, I'll visit you." can be interpreted as "If I have time, I'll visit you." or "As soon as I have time, I'll visit you."

So, @if expresses more strongly a condition. Also, as a programmer knowing several different languages I am used to the word "if" for conditionals.

Though that's just my opinion, like others here expressed their opinion. To make a proper decision, it might be good to get some statistics of what people would prefer. That should be done without biasing them to one or the other side by the question.

Sebastian

@FremyCompany
Copy link
Contributor

FremyCompany commented Oct 12, 2021

No strong opinion, but at the very least this is wrong:

In natural language, "when" is used for something that hasn't happened yet, whereas if is more synchronous.

The word "when" does not imply timing per se, the sentence (+tense) does.
For instance, as in When she arrived, everyone greeted her.

It goes against conditional naming in almost every structured language.

I think this is a stronger point.


As a rule of thumb though, I don't like @if for media queries because these things are transient and can turn on or off at any point, so @when is more indicative of that transient nature. That said, there are other things which are not transient in nature like supports() so in in the end I don't feel that strongly.

@LeaVerou
Copy link
Member Author

As a rule of thumb though, I don't like @if for media queries because these things are transient and can turn on or off at any point, so @when is more indicative of that transient nature.

FWIW in most other reactive programming languages, which by definition share this trait, conditionals are still called if. E.g. spreadsheets, Elm etc.

@FremyCompany
Copy link
Contributor

I think you are making the point that if is valid anywhere when is, in this context, (as in: it's more generic). You then concluded that if should then be used because it's the most natural for programmers around the world to express this type of branching, regardless of the fine details of the semantics. I think that's a valid point. I would clearly not oppose changing to if for that reason if there is a large majority who thinks the same.

But it doesn't mean that when is not more correct in this context, I would argue that often it is. So, if there was a vote, I would vote for the statu quo I guess.

As I saw other people ask for examples of why when is sometimes a better fit, I will propose

/* when it's sunny, sunglasses are visible but umbrellas are hidden */
@when <it's sunny> {
     .sunglasses { visibility: visible; }
     .umbrella { visibility: hidden; }
}
/* when it's overcast, both umbrellas and sunglasses are hidden */
@when <it's overcast> {
     .umbrella, .sunglasses { visibility: hidden; }
}
/* when it's raining, umbrellas are visible, but sunglasses are hidden */
@when <it's raining> {
     .umbrella { visibility: visible; }
     .sunglasses { visibility: hidden; }
}

This is my mental model of media queries (as in how I "read" them in my mind). Now I understand that other models are possible. It's not impossible to read these sentences with if instead. I just like it less (as it's less informative about the fact that this condition might change over time). It's why a vote might be the only thing that's worth doing over this. Different mental models will yield different preferences.

@FremyCompany
Copy link
Contributor

Btw, this was implicit, but to write it out: I agree with the argument we shouldn't care too much about SASS.
It's a weak argument, and if there is a clear majority preferring if, SASS shouldn't block us.

In case it's a wash, not breaking tooling should win though, for the convenience of people using these tools.

@LeaVerou
Copy link
Member Author

LeaVerou commented Oct 13, 2021

It's a weak argument, and if there is a clear majority preferring if, SASS shouldn't block us.

Do you mean when there is a clear majority? 🤪

^ Tongue in cheek, but I do think that highlights another problem with when: in natural language, using "when" implies certainty that something will happen, and only potential uncertainty as to its timing. However, in this case we don't want to imply any such certainty, as these queries may never match.

@astearns astearns moved this from Temp to Next week? in APAC Nov 3 2021 TPAC meeting Oct 29, 2021
@astearns astearns moved this from Next week? to Temp in APAC Nov 3 2021 TPAC meeting Oct 29, 2021
@svgeesus svgeesus moved this from Temp to Next week? in APAC Nov 3 2021 TPAC meeting Oct 30, 2021
@astearns astearns added this to Temp2 in December 8 meeting Dec 7, 2021
@astearns astearns moved this from Temp2 to Temp3 in December 8 meeting Dec 7, 2021
@atanassov atanassov added this to Can wait until 2022 in December 15 meeting Dec 15, 2021
@atanassov atanassov moved this from Can wait until 2022 to Everything else in December 15 meeting Dec 15, 2021
@fantasai fantasai moved this from Everything else to Can wait until 2022 in December 15 meeting Dec 15, 2021
@fantasai fantasai added the css-conditional-5 Current Work label Dec 25, 2021
@matthew-dean
Copy link

matthew-dean commented Mar 23, 2022

@romainmenke

Is it possible that sass @if can still be a superset of css @if?
As far as I can tell it's possible to detect sass @if in the syntax of the boolean condition.

I'm not a Sass expert, but you may be correct. Less does this with several functions that were added to CSS that already existed in Less, or which cannot be evaluated at compile-time (sometimes because of var()), or whose argument syntax was changed (which, I guess, didn't have heated discussions to avoid because of breaking Less and Sass, lol) to allow functions to "pass-through" if it doesn't match Less's supported syntax.

For example, this input for Less:

@my-color: #333;
.box {
  value-1: rgba(var(--my-color), 0.5);
  value-2: rgba(@my-color, 0.5);
}

...will produce this output...

.box {
  value-1: rgba(var(--my-color), 0.5);
  value-2: rgba(51, 51, 51, 0.5);
}

The downside is that the compiler can't really "validate" what's passed through (although, in general, a CSS pre-processor probably should allow invalid syntax to pass through, for various spec reasons). In other words, a Less author may have been intending to write a valid Less function, and for those special-case functions, Less will not throw an error and will instead output as-is (if a parsing / evaluation error is present).

AFAIK, Sass took a different approach of name-spacing Sass functions, and asking people to re-write existing code (I think?). But yes, in the case of @if, you could probably look at what's being tested, determine that what's being tested is either a Sass variable or these new CSS functions, and determine evaluation vs. pass-through at eval time, like Less does. 🤷‍♂️

I think another reasonable proposal mentioned above is just to alias @when to @if, because it's unlikely that if @if was used, that @when would ever be defined to mean something else. Then Sass could use @when and everyone else could use whatever makes sense in their mental model. I realize I've been generally grumpy about the whole idea (and I sincerely hope this doesn't open the door for loops), but I'm starting to get why people might want a general-purpose @if for future expansion, especially when both @media and @supports are a kind of "if statement".

@matthew-dean
Copy link

@rviscomi I presume there's a limitation where you can't test pages that don't have an explicit sourcemap linking back to an SCSS file, yet even without that, 0.8% seems pretty significant. 😬

This sort of reminds me of #SmooshGate, with the obvious difference that shipping @if wouldn't break any in-production sites; it wouldn't even break the ability to re-compile your source SCSS files; it would simply break the ability to define a "native @if" in Sass without a compatibility solution.

@meyerweb
Copy link
Member

I am definitely oversimplifying this bit, but if it gives parser errors it might be safe to add support for css @if on top of sass @if?

I’ve wondered this myself. As far as I can tell, Sass syntax is @if bare_conditional_tests {…}. CSS would seem to be @if function()s {…}. Isn’t it possible for Sass to tell the two apart at parse time and act accordingly?

@bramus
Copy link
Contributor

bramus commented Mar 23, 2022

@meyerweb In the list shared above by @rviscomi most entries indeed perform a check involving a Sass variable (e.g. $direction == down), but I did spot a few entries that only include a function. Example entries are 212 and 364: variable-exists(header-sizes) and is-light-color-scheme() respectively.

@rviscomi
Copy link

@matthew-dean that's right, we're limited by the sites that choose to provide the source mapping. We also only look at stylesheets with sourceMappingURL defined inline and not those served with the SourceMap header, but that's more of an implementation detail.

@SebastianZ
Copy link
Contributor

@romainmenke wrote:

I am almost sure this must have been considered at some point and probably is not an option but after reading through (almost) all of this thread I did not see it mentioned directly.

Is it possible that sass @if can still be a superset of css @if?

That was initially pointed out by me and later picked up by @nex3 as one possible solution with some restrictions.

Currently css @if conditionals with media(...) or supports(...) give parser errors.

That's incorrect. E.g. @if media(screen) is valid in Sass as pointed out by @nex3's comment linked to above. See also one of my previous posts.

Having said that, there are no sites using the media() function in @rviscomi's data. That doesn't mean it's never used, though it can at least be seen as indicator that it is uncommon to use it.

Though according to its documentation Sass allows any core library or user-defined function as expression within @if. So while pure function calls without variables seem to be very uncommon according to the provided data, the CSS and Sass syntaxes for the conditions currently do clash.

This means that in order to let Sass' @if be a superset of CSS' @if, this possible clash needs to be avoided. And that again means to either change the syntax of CSS or Sass.

Sebastian

@matthew-dean
Copy link

Though according to its documentation Sass allows any core library or user-defined function as expression within @if. So while pure function calls without variables seem to be very uncommon according to the provided data, the CSS and Sass syntaxes for the conditions currently do clash.

This is a slippery slope. By the same token, both Less and PostCSS allow you to also define an @if { } and, in addition, define a function for media(). But, to some degree, the risk of creating a named at-rule or named CSS function is assumed by the author (vs creating something like @-if I guess... The CSS spec doesn't really provide good guidelines / syntax / tools to pre-processors for isolating custom syntax / custom at-rules and function calls to avoid clashes, which is part of how this whole thread got here. The JavaScript community had a similar problem with early libraries extending native prototypes, until "best practices" were established, which haven't come for CSS-related libraries.)

So you end up with something like this PostCSS plugin, which has about 10,000 downloads per week.

In other words, in some sense it's good this discussion is happening, because it's clear that CSS and CSS tooling need a different approach to expanding syntax, and I think it's good that authors (and thought leaders) of CSS are taking this problem seriously.

@romainmenke
Copy link
Member

romainmenke commented Mar 24, 2022

@romainmenke wrote:

Currently css @if conditionals with media(...) or supports(...) give parser errors.

@SebastianZ wrote:

That's incorrect. E.g. @if media(screen) is valid in Sass as pointed out by @nex3's comment linked to above. See also #6684 (comment).

I missed that.
@if <function token>(<ident token>) indeed doesn't give errors in sass.
I do still keep wondering if this can not be made into a feature instead of a bug/issue.

  @if media(screen) and $light-theme {
    background-color: $light-background;
    color: $light-text;
  }

I now also realise that keeping both sass @if and css @if trades one real naming conflict for a much large amount of theoretical naming conflicts. Which is probably worse, but maybe it can work in practice?

List of function names from the conditionals posted above : https://gist.github.com/romainmenke/4cd042c331031538a441c2adf76a5c42

List of function names with <function-token>(ident-token) :

functions with vendor prefixes or _ prefixes were removed

archive-list-default
archive-list-large
checkbox
col
color
config
contains
feature-exists
font
font-size
font_size
function-exists
get-font-family
global-variable-exists
global_variable_exists
gridle_get_state_var
gridle_is_driver
included
index
media-breakpoint-up
mixin-exists
mixin_exists
output
size-ratio
space-support
style-get
type-of
type_of
use-local-scope
using
v-is-included
var
variable-exists
variable_exists
variables-exists
viewport-exists

@synecdokey
Copy link

synecdokey commented Mar 24, 2022

I write sass every day, and I would honestly take the hit of doing a search and replace once to get a syntax for the next decades that's more commonly accepted in programming languages (not just imperative ones) to the point that even the CSSWG minutes reference it as if/else, and it's also a lot easier to understand for non-native speakers.

Choosing @if does not break the web, it breaks builds, it's definitely not the situation TC39 was in with live websites breaking.

Even wikipedia doesn't even bother talking about other constructs.

@matthew-dean
Copy link

matthew-dean commented Mar 24, 2022

@synecdokey

It's a fair point. I suppose there's a fair amount of assumption that the keywords would need to co-exist, and that there's inherent conflict. But... there actually wouldn't be in practice. 🤔 Because both usages would not happen immediately for the same stylesheet author. It could be like:

  1. Sass renames @if to @when (or something else)
  2. You run the migration tool and upgrade Sass (or, yeah, just search / replace all?)
  3. Now you can use native @if
  4. If you don't want to use native @if, you stay on an older Sass version.

Basically, it wouldn't break builds. Existing files w/ existing Sass dependencies would continue to compile just fine. It's just when a Sass user wanted to use a native @if that they would need to make upgrade choices, which could be automated.

Basically, it doesn't break live code, because there's not an external compiler you don't control, and it doesn't break builds, because languages / existing files are inherently tied to a fixed compiler version. It's more like a "future compatibility question". So I wonder if people have been thinking about this in the wrong way. If browsers added @if today, it wouldn't cause anyone's Sass code to break anywhere. It's just you would need a solution when you wanted to output @if. (Which, of course, is the exact same problem if people want to output "native nesting" if that proposal moves forward.)

I'm just spitballing, I'm not sure it's the best choice, but just to point out that choosing @if wouldn't actually break anything for any users. (And apologies if someone already made this point.)

@tabatkins
Copy link
Member

It's just you would need a solution when you wanted to output @if

Given that that's precisely what you would want to do the moment you started using the CSS @if, it would be a problem immediately for such a person. This isn't a small side issue, it's the core problem that will immediately manifest for every such user.

@Marat-Tanalin
Copy link

@tabatkins

It's just you would need a solution when you wanted to output @if

Given that that's precisely what you would want to do the moment you started using the CSS @if, it would be a problem immediately for such a person.

Not as long as the preprocessor provides a way to output native CSS constructs explicitly. As said multiple times, this could be done via a prefixed rule like @css-if or @standard-if.

@tabatkins
Copy link
Member

That's been addressed multiple times already.

@Marat-Tanalin
Copy link

That, without specifics, may mean anything.

@tabatkins
Copy link
Member

I invite you to read the preceding comments in the thread that addressed the exact subject of your comment.

@matthew-dean
Copy link

matthew-dean commented Mar 26, 2022

@tabatkins

Given that that's precisely what you would want to do the moment you started using the CSS @if, it would be a problem immediately for such a person.

In practice, how? Would we not assume that if there were a conflict, Sass would have a version that addressed it before a user could reach for it? i.e. I can't envision a scenario where CSSWG picked @if, and Sass would not then address that conflict long before it was implemented in enough browsers that a user would seek to use it within Sass.

Again, there's an argument (that I've also made) that @when may be the better choice just on semantics alone. I'm just saying I can't actually see the evidence that a native @if would cause irreparable harm to Sass users. It just wouldn't. Or if this were true, then CSSWG would have avoided adding CSS functions that already existed in Sass / Less. (min() and max() existed in both Less and Sass long before they were added to CSS and caused conflicts.) And it would continue to avoid syntax clashes with pre-processors in other specs, which, as I've pointed out, it isn't!

So, again, I like @when. I think it's fine. I just don't get how @if is special in terms of conflict. It's entirely inconsistent with how CSSWG has made decisions in the past and continues to make them today in other specs. I feel that from that perspective, @LeaVerou is correct.

@jonathantneal
Copy link
Contributor

jonathantneal commented Mar 27, 2022

I appreciate the discussion, and wanted to share that I am not opposed to either @if or @when.

I am softly, less in favor of @if, and I phrase it that way on purpose.

When I’m writing JavaScript or any scripting language with if blocks, then I expect the if statement to be evaluated only when the higher closure is being evaluated.

Example 1: the if evaluates when the higher closure — the global, top-level scope — is evaluated.

if (is_truthy) doThis()

Example 2: the if evaluates when the higher closure — the runThis function — is evaluated.

const runThis = () => {
  if (is_truthy) doThis()
} 

In either example, I do not expect doThis() to run if/when something else changes the value of is_truthy.

This is the reason I am softly, less in favor of @if for CSS, because I do not share the “if” model. I especially do not share the same “if” model for anything related to media conditions. But that’s me. I’m sharing this in case it maps well for others. If it is ignored or refuted; that’s okay, too.

I want to briefly share how I positively map CSS conditionals to concepts in JS. I mentally map them to listeners, observables, and callbacks.

matchMedia('(min-width: 600px)').onchange = doThis;

matchMedia('(min-width: 600px)').addEventListener('change', doThis);

new ResizeObserver(doThis);

class extends HTMLElement {
  connectedCallback() {
    doThis(this);
  }
}

A term like @when works for me because I understand it, and it doesn’t conflict with my model for @if.

I’d survive if it were called @matches, too. :)

@simonbuerger
Copy link

@jonathantneal I actually quite like @matches... Fits my mental model too.

@meyerweb
Copy link
Member

@jonathantneal I actually quite like @matches... Fits my mental model too.

We could go math-formal and name it @given.

@matthew-dean
Copy link

matthew-dean commented Mar 28, 2022

@jonathantneal

This is a good way to articulate it. @matches or @when as it's being proposed is like "when this is true for the sheet / environment". In other words, a single state across everything at a point in time. However, the @if in Sass is like "when this is true at this point in the evaluation".

A counter-point is that a declarative language like XSLT has xsl:if although it's reserved for a single statement. For an "else-like" construct, it needs xsl:choose like:

<xsl:choose>
   <xsl:when test="number($foo) mod 2 = 0">Even<xsl:when>
   <xsl:otherwise>Odd<xsl:otherwise>
<xsl:choose>

Interestingly, @when / @otherwise or @media / @otherwise may actually be a more sound / logical pairing than @when / @else.

@meyerweb @given also sounds good for condition testing!

@cferdinandi

This comment was marked as resolved.

@vrubleg

This comment was marked as outdated.

@cferdinandi

This comment was marked as off-topic.

@astearns

This comment was marked as resolved.

@tabatkins

This comment was marked as resolved.

@matthew-dean
Copy link

Thanks @tabatkins. Sorry @cferdinandi and everyone, that was a copy paste from Stack Overflow as an XSLT example; I didn't consider the content.

@cferdinandi
Copy link

@matthew-dean All good! I didn't think you meant anything malicious by it!

@kerryj89
Copy link

kerryj89 commented Apr 7, 2022

Let's not overthink this - use @if. Let Sass team handle the change, they can adopt the unorthodox @when instead of @if and have a deprecation notice for it. They understand that conflicts like these will arise as the CSS language matures. They can create a backwards compatible @import that treats @ifs as @when (for older libraries). Let's not inconvenience ourselves forever just for the sake of preprocessors today that will continue to fade out of style as native CSS continues to grow in functionality, and trust that users will be able to spend 1 minute on a "find and replace".

@vrubleg
Copy link

vrubleg commented Sep 25, 2023

Time goes by, and @if, @elseif and @else are still the most logical keywords for this.

Sass could start to use some other prefix for their custom rules. For example, %if and %else could make it clear that it is processed by the preprocessor. It's not that hard to replace @if and @else in existing Sass files to %if and %else. A simple converter tool could be easily implemented that would automate this task.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-conditional-5 Current Work
Projects
No open projects
Development

No branches or pull requests