less / less.js

Less. The dynamic stylesheet language.
http://lesscss.org
Apache License 2.0
16.99k stars 3.41k forks source link

Nested @media blocks are combined in a non-compliant way. #3764

Open tsx opened 1 year ago

tsx commented 1 year ago

According to the CSS spec, media type (screen, print etc) must be first on the list and all the other conditions (for example (max-width: 800px)) must follow after the media type.

To reproduce:

@media (max-width: 800px) {
  @media screen {
    .selector {color: black}
  }
}

Current behavior:

Less compiler combines nested media conditions in a way that is not compliant with the spec, putting media type between conditions or after them.

@media (max-width: 800px) and screen {
  .selector {
    color: black;
  }
}

Expected behavior:

Media type should be put into the first position in the media query, like so:

@media screen and (max-width: 800px) {
  .selector {
    color: black;
  }
}

Environment information:

Additional notes

Even though it might seem trivial to re-order the example above to produce correct results, it's not always possible since the inner @media screen might come from a third party (I'm working with antd) that I can't modify.

It seems like most browsers don't mind media conditions being out of spec (or I didn't observe the effects), however this issue prevents me from using https://parceljs.org/ which implements pretty strict standards checking and chokes at the less output, producing Unexpected token Ident("screen"). The fixed snippet where media-type comes first is processed correctly by parcel.

matthew-dean commented 1 year ago

@tsx Can you link more precisely to where it specifies order?

vtclose commented 1 year ago

The spec section I linked https://drafts.csswg.org/mediaqueries-5/#typedef-media-query-list says:

<media-query> = <media-condition> | [ not | only ]? <media-type> [ and <media-condition-without-or> ]?

Which means it's either media-condition alone or media-type (like screen) followed by and ... some extra conditions. Note that media-type like screen is not a condition, so the only acceptable place for it is before the conditions.

Also see the railroad diagram in https://drafts.csswg.org/mediaqueries-5/#media if that helps to visualise things.

matthew-dean commented 1 year ago

I will just say quickly that Less doesn't parse media queries into "sections of meaning" so much as it just parses parenthetical groups, which it joins with and. Similar to the fact that it doesn't parse property values into values that could be combined, say, into a shorthand value. All of them are sequences of generic CSS tokens, with special meaning attributed only to specific tokens insofar as they might be used in functions.

So, I would say you would probably just need to re-order your media queries, because it's unlikely this would change.