Skip to content

[css-nesting-1] Clarify when nested rules are equivalents to :is() #10523

Open
@paceaux

Description

@paceaux

Could you provide clarity for when :is() is used for selectors

In the examples section, I spotted some examples that seem to suggest contradictory situations where :is() is an equivalent to the nested code.

This example suggests that :is() is an equivalent when there's a list of multiple selectors:

/* multiple selectors in the list are all
   relative to the parent */
.foo, .bar {
  color: blue;
  + .baz, &.qux { color: red; }
}
/* equivalent to
  .foo, .bar { color: blue; }
  :is(.foo, .bar) + .baz,
  :is(.foo, .bar).qux { color: red; }
*/

And this seems consistent with this example, where it is not considered to be an equivalent to an :is()

/* & doesn’t have to be at the beginning of the selector */

.foo {
  color: red;
  .parent & {
    color: blue;
  }
}
/* equivalent to
  .foo { color: red; }
  .parent .foo { color: blue; }
*/

However, I then see this example where there is not a list of selectors, but it's called an "equivalent" of an :is()

.ancestor .el {
  .other-ancestor & { color: red; }
}
/* equivalent to
  .other-ancestor :is(.ancestor .el) { color: red; }

The difference between the first and third examples is that in the first, the parent is a single selector while in the third there is a general-descendant selector. I wouldn't consider .ancestor .el to be a selector list because there's no comma indicating more selectors.

Request:
Could you please explicitly describe when nested CSS produces an equivalent to :is(). i.e.:

  • in cases where there are selector lists, the lists will be considered arguments of :is()
  • in cases where the selector is complex (having greater than 1 id, type, or class selector), it is considered an argument of :is()

Could you provide clarity on the equivalency of & and :is()

In the draft, in the section about mixing nesting rules and declarations, There is this example

article {
  color: green;
  & { color: blue; }
  color: red;
}

/* equivalent to */
article { color: green; }
:is(article) { color: blue; }
article { color: red; }

/* NOT equivalent to */
article { color: green; }
article { color: red; }
:is(article) { color: blue; }

I understand the point about order. However, I also observe an implication regarding what & does. This suggests that & will produce an :is() if it's neither preceded or seceded by another selector.

However, this contradicts an earlier example:

/* Somewhat silly, but & can be used all on its own, as well. */
.foo {
  color: blue;
  & { padding: 2ch; }
}
/* equivalent to
  .foo { color: blue; }
  .foo { padding: 2ch; }

Request
Could the incorrect example be removed? Or if they're somehow both correct, could you explain how?

Could you explicitly call out the conditions under which && would work.

The specifications give this example

/* Again, silly, but can even be doubled up. */
.foo {
  color: blue;
  && { padding: 2ch; }
}
/* equivalent to
  .foo { color: blue; }
  .foo.foo { padding: 2ch; }
*/

But it has also been made very clear that the & is not capable of sass-like concatenation.

So then what is the output of these examples?

  article {
    && {
      padding: 2ch;
  }
}

  .article {
    && {
     padding: 2ch;
  }
 }

#article {
  && {
    padding: 2ch;
  }
}

The examples, as they're given, suggest one of these produces an error:

articlearticle {
  padding: 2ch;
}

.article.article {
  padding: 2ch;
}

#article#article {
  padding: 2ch;
}

unless the & is actually always an equivalent to :is(). In which case each condition produces valid selectors:

article:is(article) {}
.article:is(.article) {}
#article:is(#article){}

But if this is the case, that contradicts this example where the & seems to be "consumed".

Request
Could you expand the "Nesting Selector" section and explain when & is an equivalent to :is(). Could you add a section that explicitly calls out how behavior may differ with a type selector? Maybe add an example of && to the slightly rephrased example with type selectors

Metadata

Metadata

Assignees

No one assigned

    Labels

    Closed as Question AnsweredUsed when the issue is more of a question than a problem, and it's been answered.css-nesting-1Current Work

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions