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

[mediaqueries][css-conditional] else #112

Closed
tabatkins opened this issue May 13, 2016 · 70 comments
Closed

[mediaqueries][css-conditional] else #112

tabatkins opened this issue May 13, 2016 · 70 comments

Comments

@tabatkins
Copy link
Member

tabatkins commented May 13, 2016

Update: Current proposal is for an @when and @else rule, and is located at https://tabatkins.github.io/specs/css-when-else/


From @frivoal:

During the face to face, we talked about the fact setting default styles outside of a media query, then undoing then in the media query before applying new ones is painful, and that authors often want to do something like if/else.

I suggest we go with this syntax:

@media (something) {
 ...
 ...
 ...
 @else {
 }
}

@supports (foo:bar) {
 ...
 ...
 ...
 @else {
 }
}

I think putting the else inside the conditional rather than following it, is more consistent with how things work in CSS, since we don't currently have a concept of associating two separate @rules.

The transition phase isn't too nice, as this isn't really usable until all browsers support it, but I think this is going to be the case for any syntax we can pick for this feature.

Thoughts?

@tabatkins
Copy link
Member Author

I don't think there's a problem with linking an @else to an immediately preceding conditional rule. It's new, but eh.

Problem with nesting, to me, is that it makes it feel like it might negate everything? Like, if you have @media ➀ { @supports ➁ { @else { ➂ } } }, it's not super clear whether the @else stuff applies solely when ➀ and !➁ (just negates the closest condition), or when !(➀ and ➁) (negates the current condition stack).

@upsuper
Copy link
Member

upsuper commented May 14, 2016

As a web developer, I'd prefer not putting it inside, which looks weird, and doesn't match the intuition from any other programming language.

As a browser developer, though, I'm concerned about how CSSOM should handle this.

Also I guess it makes sense to allow @else to precede another @media or @support, like a if-elseif structure. But that would likely make story of CSSOM more complicated.

@tabatkins
Copy link
Member Author

If we're wanting to start doing this kind of thing, people will want to do things like, say, test for both an @media and an @supports, and then have a block of code for when they're both true and both false. This means we'll want to make them combinable in a reasonable way.

Maybe instead, we just explicitly create an @if block, which can take media() and supports() conditions (like what we have for @import statements). @media/@supports would then just be special-case versions that let you write slightly shorter blocks when you only need one or the other type. Then @else (and @else-if) can be blocks that have to follow an @if or equivalent.

That is, you can start an if-chain with an @if, @media, or @supports block, then continue it with zero or more @else-if blocks (with grammar identical to @if), then an optional final @else block with no condition. You can be guaranteed that exactly one of the blocks in the chain will be evaluated.

@Marat-Tanalin
Copy link

@tabatkins While your @if/@else idea sounds good, it would probably be more clear and unambiguous if you’ve provided a code example besides just a description.

@frivoal
Copy link
Collaborator

frivoal commented May 17, 2016

@Marat-Tanalin, I take it to mean something like this:

@if media((width >= 400px) and (pointer: fine)) and supports(display: flex) {
   ...
}
@else-if supports((caret-color: pink) or (background: double-rainbow()){
  ...
}
@else {
  ...
}

@bradkemper
Copy link
Contributor

I do think "else-if" is almost as important as "else", whatever the syntax.

Would @else have to come immediately after an @if or @else-if block, or could there be rules in between? I would think the former. The latter could be useful for organizing code, but would probably lead to mistakes.

@frivoal
Copy link
Collaborator

frivoal commented May 19, 2016

Would @else have to come immediately after an @if or @else-if block

Yes, the alternative is too error prone and non obvious.

@tabatkins
Copy link
Member Author

Sorry for the delay - Florian's example is indeed exactly what I intend.

@bradkemper Yeah, definitely immediately after. A "dangling @else" (an @else or @else-if whose preceding rule was not a conditional or @else-if) would be invalid. It's technically non-ambiguous to allow interleaved rules, but it would be terrible for readability.

@fantasai
Copy link
Collaborator

fantasai commented May 24, 2016

Combinable queries seem pretty useful. The current W3C style sheet is doing a conditional against both selectors and @media, which is involving a fair bit of code duplication atm...

@tabatkins
Copy link
Member Author

tabatkins commented May 25, 2016

@fantasai I'd love to see an example of that - you're talking about mixing selectors and MQs, which isn't even on the table yet.


I've produced a draft spec for this at https://tabatkins.github.io/specs/css-when-else/. If we accept this, I intend it to be merged into Conditional.

@frivoal
Copy link
Collaborator

frivoal commented May 25, 2016

@tabatkins I've skimmed your suggested spec, and modulo some fleshing out of details (particularly the parsing and evaluation of <boolean-condition>), I approve.

@fantasai
Copy link
Collaborator

See https://www.w3.org/StyleSheets/TR/2016/base.css section marked "ToC Sidebar".

@tabatkins
Copy link
Member Author

@fantasai Looks like it's where you want "if the screen is narrow or body has .toc-inline, use the inline styling; if screen is wide or body has .toc-sidebar, use the sidebar styling"?

@fantasai
Copy link
Collaborator

Right

@tabatkins
Copy link
Member Author

tabatkins commented May 25, 2016

So I discussed this with the Sass folks today, and @if clashes with their existing rule. @else-if and @else are fine. We did some brainstorming, and I think @when works pretty well.

So we'd have @when as the combined conditional rule, @else-when for extending, and @else for finishing.

@tabatkins
Copy link
Member Author

Other possibilities brought up were @test, @cond, @where.

@tabatkins
Copy link
Member Author

@fantasai So if we pretend there's a selector() function that is true if something on the page matches that selector, I think you'd write:

@when selector(body.toc-inline) or (media(width < 28em) and not selector(body.toc-sidebar)) {
  /* inline ToC styling */
} @else {
  /* sidebar ToC styling */
}

@Marat-Tanalin
Copy link

Marat-Tanalin commented May 25, 2016

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.

By the way, why not just extend @media to use it itself as @if?

@tabatkins
Copy link
Member Author

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. In this case, I think there are several names that work just fine in place of @if.

By the way, why not just extend @media to use it itself as @if?

Are you asking why @media can't be used at the start of a conditional chain? It can be - the conditional chain just needs to be started by any conditional group rule other than @else-when or @else.

Or are you asking why we don't just extend @media to have the full value set that I've defined @when to have? That's because it would be weird; there's nothing media-like about supports queries, or about other kinds of queries we might do in the future (like the @url rule). It also would make the grammar very complicated.

@Marat-Tanalin
Copy link

Marat-Tanalin commented May 25, 2016

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.

Or are you asking why we don't just extend @media to have the full value set that I've defined @when to have?

This one.

it would be weird; there's nothing media-like about supports queries

We already have not quite media-related things like scripting in media queries. After all, extending @media is (except for placing @else as a subrule) what Florian has initially proposed.

It also would make the grammar very complicated.

I’m not sure why this:

@media ((width >= 400px) and (pointer: fine)) and supports(display: flex) {}

would be more complicated than this (at least from author’s [not spec writer’s] perspective):

@if media((width >= 400px) and (pointer: fine)) and supports(display: flex) {}

The media code could even be simpler without redundant parens:

@media (width >= 400px) and (pointer: fine) and supports(display: flex) {}

@tabatkins
Copy link
Member Author

If we were, today, trying to invent supports queries, and someone suggested just putting them into our sole existing conditional rule (@media), I'd be receptive. But we aren't - we already have two specialized conditional rules that handle different kinds of things (and a third that was proposed and exists in Firefox user-level stylesheets), so it's weird to privilege one of them.

Also, media queries have a weird legacy syntax with their media types that makes this a little stranger. Overall not that great. Starting fresh and putting all the types of queries on an equal footing is simple and easy.

@frivoal
Copy link
Collaborator

frivoal commented May 26, 2016

@tabatkins between the alternative you proposed, I like @when best. @cond is nice for people who know lisp, but that's not a whole lot of people, and everyone else is going to find it obscure. @test or @where aren't necessarily that bad, but I like them less.

I'm also in favor of allowing @else after any kind of conditional rule (@media, @supports, @when, @document if we ever get it...)

@upsuper
Copy link
Member

upsuper commented May 26, 2016

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?

@xzyfer
Copy link

xzyfer commented May 26, 2016

IMHO Sass is an incumbent technology, so purposely colliding with it is akin to "breaking the web". This issue ring similar to the array.contains issue faced by TC39.

Sass will get out of the way as much as possible, but an @if like this could potentially force a python 3 style split that community.

What's the percentage?

Hard to say for sure. A couple recent developer surveys put Sass usage at about 60%-70% of respondents.

preprocessors can always work around that easily

This is generally true for when CSS does something new that preprocessors didn't previously do, like custom properties for example.

However in the CSS of adopting an existing syntax there is no good work around for preprocessor authors. Best case they release a new major with a new syntax. Doing so breaks the existing community of packages.

Even if all package were updated, there is always a significant percentage of people who cannot update for reasons like internal processes, or software. These users are affected the worse because they are left completely unable to use this feature.

@upsuper
Copy link
Member

upsuper commented May 26, 2016

This issue ring similar to the array.contains issue faced by TC39.

This isn't. The original Sass file before preprocessing is not processed directly by browsers.

However in the CSS of adopting an existing syntax there is no good work around for preprocessor authors. Best case they release a new major with a new syntax.

Workaround shouldn't be too hard. As @Marat-Tanalin mentioned, they can keep their existing @if and introduce a new keyword like @css-if which is converted to the CSS's @if during preprocessing. What's the problem with this workaround?

@xzyfer
Copy link

xzyfer commented May 26, 2016

The original Sass file before preprocessing is not processed directly by browsers.

True, but it leaves the author unable to use the CSS @if syntax.

new keyword like @css-if which is converted to the CSS's @if

Also true. This shifts the burden off from the existing ecosystem and onto the everyday developers.


Aside from technology I think there are real concerns regarding the effects on the wider CSS and Sass communities, some potential examples:

Raising the barrier to entry by negatively affecting google search results for the correct syntax for a given context i.e. authoring in CSS or Sass.

Causing confusion where-in blog authors would need to explicitly declare CSS @if or Sass @if in their content.

@upsuper
Copy link
Member

upsuper commented May 26, 2016

Actually it seems to me it is even possible for preprocessors to integrate the new CSS @if with their existing one, so that authors wouldn't need to distinguish between the two @ifs, and CSS's @if would be generated when the preprocessor thinks it should do.

Since CSS's @if is somehow a syntax sugar of existing syntax, the preprocessors can generate the old syntax if requested before all browsers ship the support of the new syntax.

@xzyfer
Copy link

xzyfer commented May 26, 2016

it is even possible for preprocessors to integrate the new CSS @if with their existing one

I don't believe this is possible. Just about every part of the proposed syntax collides with Sass.

The breakpoint and supports functions are common user defined functions in all major preprocessors. Given that I'm not sure if it's possible disambiguate between the Sass and CSS @if.

Where as the earlier @media (..) { } @else { }, and by extension the suggested @when (...) { } @else { } is unambiguous.

when the preprocessor thinks it should do

This comes off a bit hand-wavey, although I'd be curious to hear how you think the preprocessor would know. This is something Sass has talked about doing for @extends -> matches() some day.

@heycam
Copy link
Contributor

heycam commented Nov 7, 2018

Another option if we want to avoid the awkwardness of where the @else or @not would go is to have an at rule that contains all of the conditions to check. Strawperson:

@switch media {
  (min-width: 800px) { /* rules */ }
  (min-width: 600px) { /* rules */ }
  default { /* rules */ }
}

@switch supports {
  (color: rainbow) { /* rules */ }
  default { /* rules */ }
}

Not sure how well that works for backwards compat.

@heycam
Copy link
Contributor

heycam commented Nov 7, 2018

(And maybe you'd want to just have a single @switch with both MQs and supports conditions inside it.)

@frivoal
Copy link
Collaborator

frivoal commented Jan 7, 2019

It feels like @heycam's suggestion would also be gentler on the OM than an @if {} @else {}
Converting my earlier example:

@if media((width >= 400px) and (pointer: fine)) and supports(display: flex) {
   ...
}
@else-if supports((caret-color: pink) or (background: double-rainbow()){
  ...
}
@else {
  ...
}

becomes

@switch {
  media((width >= 400px) and (pointer: fine)) and supports(display: flex) {
     ...
  }
  supports((caret-color: pink) or (background: double-rainbow()){
    ...
  }
  default {
    ...
  }
}

This seems quite workable to me.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed else conditional.

The full IRC log of that discussion <astearns> topic: else conditional
<jensimmons> people aren’t really using the media query. they will use thr property a lot
<astearns> github: https://github.com//issues/112
<fremy> TabAtkins: heycam wanted to put this on the agenda, and I'd be interested to know why he brought this up
<fremy> heycam: I made a proposal and it never got discussed further
<TabAtkins> http://tabatkins.github.io/specs/css-when-else/
<fremy> TabAtkins: yeah, I had limited time so I didn't push forward, but if there is interest I can reprioritize my work
<fremy> astearns: so, heycam, are you volounteering to implement that?
<fremy> heycam: no
<fremy> TabAtkins: in that case, I'd rather leave this in the status of proposal
<fremy> fantasai: could we maybe cross-link the issue in the draft, so this discussion is available to readers?
<fremy> TabAtkins: okay, sounds reasonable
<fremy> TabAtkins: it's not right now, but I can do this
<fremy> heycam: so, shall we table this discussion for now?
<fremy> florian: just wanted to note that also unless everybody is doing it, it's not useful
<fremy> myles_: sure, but if one does it and authors finds it useful, others will follow
<fremy> TabAtkins: but the point is that right now we don't even have one promise to implement
<fremy> astearns: okay, let's try to do easing timing functions, then take a break

@tabatkins
Copy link
Member Author

The reason I didn't like @switch equivalents is that it still only lets you test on a single type of conditional at a time. If you want to test for a MQ and an SQ, or else do something else, you can't write that reasonably in @switch.

That is:

@switch {
  @media A {
    @supports B {
      /* code intended for (A && B) */
    }
  }
  @media not A {
    /* code intended for (!A) 
       aka (!A && B) or (!A && !B) */
  }
  @default {
    /* code intended for (A && !B),
       the leftover case */
  }
}

will never run the @default block (because the two top-level rules fully cover A and not A), even if the intention is to have it contain code for when A is true but B is false.

Versus when/else, which would handle it well:

@when media(A) and supports(B) {
  /* (A && B) */
}
@else media(not A) {
  /* (!A), which is (!A && B) || (!A && !B) */
}
@else {
  /* (A && !B) */
}

I don't think it's possible to mod @switch into doing this, because the top-level rules aren't constrained to contain only a single child conditional; it could have several, so you can't easily tell what cases it's supposed to cover (and thus what "default" should cover).

@ByteEater-pl
Copy link

@when is familiar to those who know SQL which has WHEN in both variants of its CASE expression and no IF.

@astearns
Copy link
Member

In a discussion about @supports rules for @container we briefly discussed allowing @else after any at-rule

#6175 (comment)

@heycam
Copy link
Contributor

heycam commented Apr 28, 2021

I don't think it's possible to mod @switch into doing this, because the top-level rules aren't constrained to contain only a single child conditional; it could have several, so you can't easily tell what cases it's supposed to cover (and thus what "default" should cover).

Do I remember correctly that we've previously discussed having a supports() function that can be used in media queries? I couldn't find the discussion after a brief search. With it, you could make @switch always take media query expressions:

@switch {
    (max-width: 400px) and supports(abc: def) { ... }
    not (max-width: 400px) { ... }
    default { ... }
}

@LeaVerou
Copy link
Member

LeaVerou commented Sep 15, 2021

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
Copy link
Contributor

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.

@svgeesus
Copy link
Contributor

The CSS Working Group just discussed Nesting @supports inside @font-face / font tech queries, and agreed to the following:

  • RESOLVED: Adopt if/else as next level of css-conditional
  • RESOLVED: Accept the PR
The full IRC log of that discussion <fantasai> Topic: Nesting @supports inside @font-face / font tech queries
<fantasai> github: https://github.com//issues/6520
<fantasai> chris: Basic problem is that we need a way to ensure that only one of the possible options works
<fantasai> chris: if you have unicode-range and a character outside that range, all the others will be loaded to see if it has that char
<fantasai> chris: so this has been paired with another issue
<fantasai> chris: It seems we need to discuss together
<fantasai> lea: Looks like primary problem with using @supports is that pattern
<fantasai> lea: of older code being unwrapped, but wrapping new code in @supports
<fantasai> lea: but that doesn't work well with @font-face
<fantasai> lea: because the second rule doesn't override the first rule
<fantasai> lea: they combine to form a single family
<fantasai> lea: although normally only second font is used
<chris> q+ to add that the existing format overload does have the "only one wins" characteristic
<fantasai> lea: if browser encounters character not in the second, it will download the first to check if it is there
<fantasai> lea: so for this we would need an else condition
<fantasai> lea: so that we never have both @font-face rules in effect at the same time
<fantasai> lea: There's a proposal from Tab to combine feature queries and media queries, and has else
<drott> q+
<fantasai> lea: Tab suspects it's easy to implement
<fantasai> lea: if this can be implemented together with font-technology(), that would be nice
<fantasai> lea: concern that if implement without it, we'll have this problematic pattern
<astearns> ack chris
<Zakim> chris, you wanted to add that the existing format overload does have the "only one wins" characteristic
<fantasai> chris: Overloading the format string does have this benefit of combining the conditionals properly
<lea> q?
<fantasai> chris: if we don't rapidly converge, we'll be stuck with that
<fantasai> astearns: So you're concerned to get if/else quickly so that practice doesn't ossify into bad syntax
<fantasai> chris: people will just ship what's in the spec now
<fantasai> myles: I thought we would remove the complicated resource grammar
<astearns> ack drott
<fantasai> drott: I spoke to implementers, to Anders and Rune who are familiar with our CSS code
<fantasai> drott: They have no immediate concerns with the when/else proposal
<fantasai> drott: Which brings my question of timing
<chris> \0/ to no concerns!
<fantasai> drott: I'm also supportive of removing the syntax in the spec now
<fantasai> drott: but eager to have something to enable font tech feature testing atm
<fantasai> drott: We're supportive of the when/else proposal, but it would be better to have font tech queries soon and maybe when/else as an upgrade path
<fantasai> astearns: Is it possible to have a font-tech syntax in the @font-face that would handle the conditional?
<fantasai> drott: Current feature in spec is encapsulated in src descriptor
<fantasai> drott: in the format() function
<fantasai> drott: Authors can order it by most advanced tech, and then the UA will pick the one that it supports
<fantasai> drott: In current proposal, without @else we have an accumulation of fonts into the family
<lea> astearns: https://drafts.csswg.org/css-fonts-4/#font-face-src-parsing
<lea> ^ that is the current syntax
<fantasai> astearns: Would it be possible to have a limited state for this font technology where you could put it into your @font-face and have a font face exist if the font technology was supported, but have it not exist if it wasn't
<fantasai> astearns: no fallback, just make this font face if the tech is supported
<fantasai> drott: You could use different families
<fantasai> lea: If you don't want fallback, that's fine. You just make an @font-face
<fantasai> astearns: so wanted to remove things from spec, remove the current syntax
<fantasai> astearns: in favor of clearer if/else
<fantasai> astearns: but people still want conditional on font
<fantasai> astearns: and it would be nice to have that font tech
<fantasai> chris: we need to do both
<fantasai> chris: for a solution
<drott> fantasai: I think we had previous notes on this, can't find it
<drott> fantasai: it was basically: we should have both, the font-technology function in @supports, and the ability to query the tech in the format function, and they should share the syntax. And the syntax should be simpler.
<astearns> s/would handle the conditional/would not handle the conditional with fallback/
<chris> q+
<drott> fantasai: for @supports, you might want to query not only if it's color, but you might want to query for format
<drott> fantasai: I would simplify the syntax of the font-technology function.
<drott> q+
<drott> fantasai: In a way to remove the sub functions, and just have a list of keywords, for example font-format-...
<fantasai> fantasai: ....
<fantasai> drott: I think you did post it somewhere, I had updated my pull request to flatten it...
<fantasai> chris: ...
<drott> q-
<lea> q?
<lea> q+
<fantasai> chris: The format shouldn't be the orphan that gets left behind that you have to do in src, it should be same conditional thing that we do in font-technology
<fantasai> chris: so if woff5 comes along, we can also put that in this new shiny syntax
<astearns> ack chris
<drott> fantasai: it should be the same function, for format and font technology
<chris> I don't really like calling it font-format
<fantasai> lea: If I understand correctly, a format should also have been a condition in @supports
<chris> yes exactly lea
<fantasai> lea: if designing today that's how we would do that
<fantasai> lea: only reason we have format function is that it's legacy
<chris> we can't get *rid* of the format legacy though, so it has to remain in the spec
<fantasai> lea: so I think what Chris is saying is that we also need to be adding a font-format() function into @supports so that authors can combine @font-technology queries
<fantasai> lea: whereas what fantasai is saying is to have only format() function, and have it allowed both in src and @supports
<fantasai> s/chris: .../lea: I think that was my proposal to flatten from color() to color-/
<fantasai> astearns: So we're looking for a way to express simper supports queries in @font-face rules
<fantasai> astearns: and remove fallback ability
<drott> fantasai: I think we're not aiming to remove fallback
<fantasai> chris: The things that drott proposed, it would be helpful to allow that as a direct query in @supports conditions
<fantasai> myles: I think adding that should be blocked on having some way of solving the problem that jfkthame described
<drott> q+
<astearns> ack lea
<fantasai> astearns: ?
<fantasai> lea: No way to do else, so authors will need to negate their queries
<fantasai> lea: and it would get very verbose and complicated
<fantasai> myles: not even sure if it's possible
<fantasai> myles: because there's a third value here, not just supported or not supported, but also case of "browser doesn't know what you're talking about"
<fantasai> chris: So need a resolution on proposal, but also how do we move forward on Tab's draft
<fantasai> chris: Can we adopt it as an ED?
<fantasai> myles: We should split this font-specific issue
<fantasai> myles: one piece blocked on else rule and one that isn't
<drott> q?
<fantasai> myles: and discuss else rule in its own CSSWG issue
<astearns> ack drott
<fantasai> drott: I discussed this issue with jfkthame offline. I think he's here?
<chris> this is its issue: https://github.com//issues/112
<fantasai> drott: In our question, jfkthame expressed some flexibility regarding timing
<fantasai> drott: I'd like to emphasize what chris was saying earlier, if we move the supports syntax from CSS as it is now, then we don't have anything to do feature testing
<fantasai> drott: I consider @supports an upgrade path
<fantasai> myles: I've heard some people say they want to remove unimplemented flexbility in the spec now, and others don't want to remove it but to reformulate to make it simpler
<fantasai> myles: either one is reasonable to me
<fantasai> lea: which part is blocked on what?
<fantasai> myles: If we want to keep the unimplemented features of the format() in src, we wouldn't need to be blocked on else
<TabAtkins> It is true that `@supports unknown-font-thing() {...} @support not (unknown-font-thing()) {...}` will fail to match both of them (the first is unknown, treated as false; the second is negated unknown, which is still unknown and thus treated as false)
<fantasai> lea: the problem with that is that we don't want microsyntaxes
<TabAtkins> whereas `@support unknown-font-thing() {...} @else {...}` would match one or the other, guaranteed.
<lea> q+
<astearns> ack lea
<fantasai> lea: Important point from the issue drott raised hasn't be raised yet
<fantasai> lea: else is syntactic sugar for negation
<fantasai> lea: but another way to work around is to use unicode-range
<fantasai> lea: drott mentioned that most font-face rules are generated, and have unicode-range alreay
<fantasai> lea: which means this isn't a problem
<fantasai> myles: unicode-range is an orthogonal feature
<TabAtkins> Oh wait, sorry, I was wrong - @supports doesn't use the unknown value.
<fantasai> myles: if author is trying to use fancy syntax that is / isn't supported
<TabAtkins> We resolved on that a bit ago.
<fantasai> myles: both @font-face rule and fallback will have the same unicode-range
<TabAtkins> Unknown things are just false in @supports.
<fantasai> myles: so the problem still applies
<fantasai> lea: Problem is if the character is not included in the range
<fantasai> myles: problem that I'm concerned about is that character is inside the unicode-range block, but not supported by the font's CMAP table
<fantasai> myles: in that case the browser will download both fonts serially
<fantasai> drott: Should have unicode-range identical to CMAP
<TabAtkins> So my statement above was wrong - both are equivalent, and you'll definitely select one or the other. (We use unknown for @media, where the browser very well *might* match an unknown query once it starts supporting it; a browser that doesn't understand a feature, by definition, doesn't support it, so that's a safe `false`.)
<drott> fantasai: Lea was concerned about multiple different microsyntaxes. My proposal doesn't do that. Format function, should have identical syntax, whether it's in src: or in @supports.
<lea> q+
<astearns> ack fantasai
<drott> fantasai: If that's the case, we can ship src: first - ship @supports version later.
<drott> q+
<astearns> ack lea
<fantasai> lea: There's another unexplored option
<fantasai> lea: what if we had an inline conditional function that does supports queries
<fantasai> lea: A supports() or supports-if() function to put inside any value
<fantasai> astearns: I think it would be a good idea to write down what you're suggesting, Lea
<fantasai> astearns: but getting a proliferation of options, unsure we can get to resolution on anything specific today
<astearns> ack drott
<fantasai> astearns: I think we can resolve at least that we would like to work on the if/else syntax
<fantasai> TabAtkins: Adopt as an ED in the WG? Currently draft in my personal repo
<lea> +1 to working on @else proposal
<jfkthame> +1
<fantasai> astearns: resolution would be to adopt, yes
<fantasai> fantasai: so that would be css-conditional-3?
<fantasai> TabAtkins: sure
<drott> q+
<astearns> ack drott
<fantasai> drott: potentially add any resolution, then idea would be to have a font-tech function to combine with that?
<TabAtkins> I also was udner the impression that Conditional started with 1.
<fantasai> dbaron[m]: I think conditional-3 is already advanced
<drott> +1 to that.
<fantasai> fantasai: oh, I meant whatever's next
<drott> sorry, fantasai, I did not capture what you said.
<fantasai> RESOLVED: Adopt if/else as next level of css-conditional
<fantasai> astearns: So question of current font-technology draft and reworking them with existence of if/else in mind
<fantasai> astearns: so take back to issue to determine what changes, if any, need to be made
<fantasai> chris: I don't see a dependency there
<fantasai> chris: I think we can adopt PR as-is
<drott> +1 as well
<fantasai> lea: +1
<fantasai> lea: this is something useful immediately
<TabAtkins> +1
<drott> zes
<fantasai> astearns: Adopting PR will resolve the issue?
<drott> s/zes/yes
<fantasai> lea: the bulk of it
<fantasai> astearns: And we can open new more tightly constrianed issues
<fantasai> astearns: So proposed resolution?
<fantasai> drott: Adds font-technology() function to @supports, which has a flat list of font technologies and options, which can be used inside an @supports rule
<drott> https://github.com/drott/csswg-drafts/commit/62cfd95a5f52604c952e4aa37be6e4d6386f88f5
<fantasai> myles: the @else rule should make it clear that it works with this new query inside @supports
<fantasai> myles: either explicitly or implicitly
<fantasai> myles: And i'd ask implementers not to implement font-technology() without @else
<fantasai> myles: because if you oonly give ability to do it wrong, people will do it wrong
<fantasai> lea: why?
<dbaron[m]> That request to implementers should be �in the spec�.
<fantasai> myles: because @else is the solution to this problem, so one depends on the other
<jensimmons> +1 to myles
<lea> s/lea: why?/lea: they can still do it right, it's just tedious/
<drott> fantasai: I am not sure, I agree with this particular PR.
<dbaron[m]> s/sure,/sure/
<drott> fantasai: I think the function should have identical syntax to what we should have in src:.
<drott> q+
<drott> fantasai: one question I have: font-technology - would this be allowed to be queries in src:?
<drott> s/queried/queries
<drott> s/queried/queries/
<fantasai> astearns: I think we should merge it in and take separate issues
<fantasai> chris: I edit both specs anyway
<drott> +1 to that, if we can have the font-technology PR
<fantasai> myles: but if we're making src less flexible than it is to day (in ths spec)
<astearns> ack drott
<fantasai> fantasai: happy to do so, as long as we can work on it and not just ship what's in the PR
<chris> @drott I see the PR on your fork repo but not the one on the csswg repo
<fantasai> myles: I think it's OK to resolve this, I think fantasai's idea about making them match makes sense to me
<fantasai> myles: I think making them match gives drott a path to implementing that doesn't rely on us standadizing a big new feature
<fantasai> myles: so I think that's the best path forward
<fantasai> astearns: we're not got to solve everything today
<fantasai> astearns: so let's merge the PR and file more issues
<drott> +1
<lea> +1
<chris> +1
<fantasai> astearns: any objections?
<fantasai> RESOLVED: Accept the PR
<chris> :)
<fantasai> myles: Can we add a note to the PR to say "don't implement this yet, implement this other thing first"
<fantasai> astearns: open an issue

@xfq
Copy link
Member

xfq commented Sep 18, 2021

Since @frivoal mentioned Lisp in #112 (comment) , as a developer who has written a lot of Lisp, I would like to mention that if and when are obviously different for many Lisp developers and the difference may cause some misunderstandings.

For example, in Common Lisp, if chooses between the then-form and the else-form based on the value of the test-form, while when is a variant of if where there are no else-form, and possibly several then-forms. (Other dialects like Racket and Clojure are the same.)

@matthew-dean
Copy link

I think it's implied in the top comment, but would this be valid?

@media (min-width: 640px) {
 // stuff
}
@else {
  // other stuff
}

@supports (display: grid) {
 // stuff
}
@else {
  // other stuff
}

@LeaVerou
Copy link
Member

@matthew-dean Yes. Which actually brings up an interesting point: Browsers could implement this now and CSS authors would get a lot of value, without waiting for the WG to resolve on the very divisive #6684 .

@matthew-dean
Copy link

matthew-dean commented Mar 23, 2022

@LeaVerou I agree. It actually feels less, er, scripty? Than @if / @when? And what I've seen so far just embeds new supports() or media() functions, so I'm not understanding why @if and @when are even needed. You can't define global variables in CSS yet, which is the typical use case for @if in Sass (and the same when guard construct in Less), so why not just do @supports / @else and @media / @else if that's all CSS wants to use an @if / @when for? 🤔 Are there really instances where CSS authors have been jonesing to put a media query and a supports test on one line?

Seems like there could be two proposals: one initial one just for @else. Then later, decide if anything else (ha) is needed (like if CSS adds global / stylesheet variables).

@LeaVerou
Copy link
Member

@matthew-dean @if allows combining these two criteria with arbitrary boolean operators, and is also an extensibility point for future conditionals as well.

@inoas
Copy link

inoas commented Mar 23, 2022

Generally speaking I'd prefer something that is more like switch/case with guards than if/else to exist in css.

Example without guards:

@case (@supports(display: grid), @supports(display: flex)) {
 (TRUE, TRUE) -> {
   body { display: grid }
 },
 (_, TRUE) {
   body { display: flex }
 },
},

Long nested chains of if/else without exhaustiveness, feel generally bad to me.

@tabatkins
Copy link
Member Author

Yeah, @when is purely a way to combine an @supports and @media query together in a single conditional; without this, you have to nest and repeat yourself in a way that's both hard to write and hard to read.

@matthew-dean
Copy link

matthew-dean commented Mar 23, 2022

@tabatkins

Yeah, https://github.com/when is purely a way to combine an https://github.com/supports and https://github.com/media query together in a single conditional; without this, you have to nest and repeat yourself in a way that's both hard to write and hard to read.

I guess I'm trying to think of a use case where one would combine @media and @supports, and then would need to exclude those criteria in an @else. I get these are both types of queries but I guess I've never seen an intersection or a coupling of the two ideas, where the media properties were linked to the supports test in some way. 🤔

The spec example says:

For example, here’s a (somewhat silly) conditional chain

But are there non-silly, logical connections between @media and @supports? Commonly enough that there's been a need to combine these into single-line queries? Any real-world examples? I'm not saying there aren't--I'm legitimately curious because I haven't encountered this.

@LeaVerou

is also an extensibility point for future conditionals as well.

Yeah, I get this, and it makes sense to some degree. I do wish we could already define / test stylesheet vars, like:

@var {
   --theme: 'dark';
}

/** extend var() to look at globals first, not just cascade :root props, so that could use var() in queries **/
@when (var(--theme) = 'dark') {
  .box {
    background: black;
    color: white;
  }
} @else {
  .box {
    background: white;
    color: black;
  }
}

Or, the inline form, I guess:

  .box {
    background: if(var(--theme) = 'dark', black, white);
    color: if(var(--theme) = 'dark', white, black);
  }

@tabatkins
Copy link
Member Author

I guess I'm trying to think of a use case where one would combine @media and @supports, and then would need to exclude those criteria in an @else.

Say you wanted to use Grid to layout the page when the viewport is wide enough. If you're being extra-careful, you may want to test for grid support as well; if either grid isn't supported or the viewport is narrow, you default to a simple block-based layout.

@CharfeddineMohamedAli
Copy link

CharfeddineMohamedAli commented Apr 3, 2022

Sass developers have 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.
But what about introducing new syntax ?
@if can be changed to @whether or @either and@else can be changed to @or

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests