Skip to content

[style-value-parser] Fix media queries with a leading not - #2001

Open
henryqdineen wants to merge 1 commit into
meta:mainfrom
henryqdineen:hqd-fix-leading-not-media-query
Open

henryqdineen wants to merge 1 commit into
meta:mainfrom
henryqdineen:hqd-fix-leading-not-media-query

Conversation

@henryqdineen

Copy link
Copy Markdown
Collaborator

What changed / motivation ?

Since #1888 (unreleased), a media query with a leading not compiles to @media not all, which never matches. For example, @media not all and (monochrome) becomes @media not all, and #1888's snapshots assert that output. An agent noticed it. In CSS, a leading not negates the whole query, but the parser read it as negating only the media type.

The fix:

  • Parse not <type> and <conditions> as a negation of the whole query, and print a standalone one as written.
  • When last-media-query-wins negates a query, push the not inward before resolving media types, so the output grows linearly instead of exponentially.
  • Keep parentheses around an or nested inside an and, and flatten nested ands so a media type always ends up first.

Linked PR/Issues

Follow-up to #1888. Related: #1199.

Additional Context

Inline snapshot tests were added in media-query-transform-test.js and transform-stylex-create-test.js, and #1888's snapshots were reverted to not all and (monochrome). I also compared the output against matchMedia in Chromium on 6,000 random query lists: main was wrong on about 40%, this branch on none.

Known gap, not changed here: a negated min-height becomes max-height: N.99px, which Chromium rounds to the breakpoint (same as main; see #1858 and #1859). I'll fix that separately.

Pre-flight checklist

🤖 Generated with Claude Code

In CSS a leading `not` negates the whole media query: `not all and
(monochrome)` means `not (all and (monochrome))`. The parser bound the `not`
to the media type alone, reading it as `(not all) and (monochrome)`.

That used to round-trip back to the original string, so it went unnoticed.
meta#1888 added media-type resolution, which simplifies the misread tree into
wrong CSS: on main, `not all and (monochrome)` compiles to `not all` (never
matches) and `not screen and (min-width: 100px)` to `print and (min-width:
100px)`. meta#1888 updated three snapshots to that output. 0.19.1 is also wrong
when such a query is combined with other media queries on the same property:
the leading `not` swallows the appended negations, or produces `(not not
all)`.

- Parse `not <type> and <condition>` as `not (<type> and <condition>)`.
- Keep a standalone leading-`not` query in that form when serializing, so
  it still compiles to exactly what was written. The three meta#1888 snapshots
  go back to their original strings. Only combined queries are rewritten.
- When resolving a negation, apply De Morgan before expanding the operand.
  Expanding first made `not screen and ((a) or (b) or ...)` grow
  combinatorially once combined with another query.
- Parenthesize an `or` inside an `and` when serializing. Without this,
  `(min-width: 1px) and ((max-width: 2px) or (max-height: 3px))` lost its
  inner parentheses and became invalid (already broken on main).
- Flatten nested `and` rules while resolving media types, so a media type
  from a negated later query moves to the front instead of ending up
  mid-query (`(max-width: 900px) and print and ...`, already broken on main
  for `not print, (max-width: 100px)`).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@vercel

vercel Bot commented Oct 31, 2026

Copy link
Copy Markdown

@henryqdineen is attempting to deploy a commit to the Meta Open Source Team on Vercel.

A member of the Team first needs to authorize it.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 31, 2026
@henryqdineen
henryqdineen marked this pull request as ready for review October 31, 2026 19:29

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant