Skip to content

[v4] \--minify\ corrupts \space-y-*\ selectors (drops :where(& but keeps closing )) #20121

@pmcgeehan

Description

@pmcgeehan

--minify produces invalid selectors for space-y-* (CSS Nesting + :where() mishandled)

Summary

When @tailwindcss/cli@4.3.0 builds with --minify, every space-y-N utility produces an invalid selector with a stray closing paren that browsers silently reject. The unminified output is correct; the minifier (lightningcss path) is stripping the :where(& opening but keeping the matching ).

Versions

  • @tailwindcss/cli@4.3.0
  • tailwindcss@4.3.0
  • Node 18.x / macOS 14
  • Browsers verified: Chrome 130, Safari 18 — both silently ignore the rule

Repro

Minimal input.css:

@import "tailwindcss";

A page that uses any space-y-N class (e.g. <div class="space-y-12"><p>a</p><p>b</p></div>).

Unminified — correct

npx tailwindcss -i input.css -o out.css
grep -A 6 '\.space-y-12 {' out.css
.space-y-12 {
  :where(& > :not(:last-child)) {
    --tw-space-y-reverse: 0;
    margin-block-start: calc(calc(var(--spacing) * 12) * var(--tw-space-y-reverse));
    margin-block-end: calc(calc(var(--spacing) * 12) * calc(1 - var(--tw-space-y-reverse)));
  }
}

✅ Valid CSS Nesting. Renders correctly in Chrome 112+ / Safari 16.5+ / Firefox 117+.

Minified — invalid

npx tailwindcss -i input.css -o out.min.css --minify
grep -oE '\.space-y-12[^,{}]*\{[^}]*\}' out.min.css
.space-y-12>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 12) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 12) * calc(1 - var(--tw-space-y-reverse)))}

❌ Note the trailing :not(:last-child)) — the :where(& was stripped but the closing paren survived. Browsers parse this as an invalid selector and discard the entire rule. No console warning is emitted.

Expected

Minified output should produce a selector equivalent to the unminified rule, e.g.:

:where(.space-y-12>:not(:last-child)){--tw-space-y-reverse:0; ...}

or any other valid flattening that preserves the :where(...) specificity (0,0,0) intent.

Impact

  • Affects the entire space-y-* family (every numeric value). Presumably space-x-* too — they share the same generation path.
  • Silent failure mode: no console error, no build warning. Bug surfaces only when developers notice that vertical spacing isn't applying as expected. Trial-and-error debugging led us through stale-bundle / browser-cache theories before fetching the deployed CSS via curl and grepping the rule.
  • Workaround: drop --minify (we ship +1 KB gzipped to restore correct behavior) or replace space-y-N calls with flex flex-col gap-N (works identically for block-flow layouts).

Probable root cause

The bug is in how the minifier flattens nested CSS containing :where(& > ...). The opening :where( and the & parent reference are dropped (presumably collapsed into the parent selector) but the matching ) is not removed. Similar nested-rule patterns without :where() may need verifying — we only tested space-y-*, but any utility emitting selector { :where(& ...) { ... } } is a candidate.

Other Tailwind utilities verified clean under --minify

mt-*, mb-*, mx-*, my-*, gap-*, gap-x-*, gap-y-*, flex, flex-col, plus all the standard utility-classes we render in production. The bug appears isolated to utilities that emit :where(& > :not(...)) patterns.

Related

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions