NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #2041 most downloaded on npm
Safe defaults for cssnano which require minimal configuration.
Last release today
03 Oct 2026
Release timing varies
gaps range from 8 days to 4 months
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
9 years old
112 releases · first in 2017
fix(postcss-merge-rules): avoid infinite loop in #2013
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@9.2.1...cssnano@9.2.2
Fix an infinite loop: when equal @media blocks were separated by an at-rule such as @layer x;, @font-face or @page, the plugin would keep merging a rule into itself until memory ran out.
Fix a bug when the plugin moved a rule into a block nested inside another block: a later merge could combine two rules in reverse order and change which declaration wins.
fix(postcss-discard-duplicates): remove redundant sibling at-rules in #2010
One column per quarter.
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@9.2.0...cssnano@9.2.1
Remove a declaration that a later sibling @media, @supports, @container or named @layer block with identical conditions repeats, so duplicates are dropped before postcss-merge-rules joins the blocks.
Keep an earlier duplicate @media, @supports or @container block that declares an @layer, so removing it no longer moves the layer's first appearance and changes the layer order. Also keep a rule that holds a /*! comment when its declarations are removed.
Keep a duplicate @import, so removing the earlier copy no longer changes the layer order.
Keep "revert-rule" quoted in font-family because revert-rule is a CSS-wide keyword.
Recognise revert-rule as a CSS-wide keyword. postcss-ordered-values no longer reorders a border, animation, transition, list-style, box-shadow or grid-row value as if revert-rule were a color, name or type. The reserved keywords are now generated from @webref/css.
Merge box alignment properties into the place-content , place-items and place-self shorthands, such as align-items:center;justify-items:start into pla
place-content, place-items and place-self shorthands, such as align-items:center;justify-items:start into place-items:center start. This only happens when every browser in your Browserslist targets supports the shorthands, because a browser that does not would ignore both alignments. The defaults query includes browsers with unknown support, such as Opera Mini and UC Browser, so it keeps the longhands. Values that use safe, unsafe or last baseline merge only when both values use the same keywords. postcss-merge-longhand now accepts the Browserslist options overrideBrowserslist, stats, path and env.Write numbers in scientific notation when it is shorter, such as 1e-6px for 0.000001px and 1e6px for 1000000px. This also applies when length unit conversion is disabled. Numbers written without a decimal point, such as z-index:1000000, keep their form, because an <integer> cannot use scientific notation.
Stop merging longhands across a nested rule or at-rule. The shorthand ended up after the nested rule and overrode it, so in a{margin-top:1px;&{margin-top:2px}…} the nested margin-top was lost. This applies to margin, padding, border, border-radius and columns. Declarations on each side of a nested rule are now merged separately. An at-rule without a block, such as @apply x;, also separates them, since it may add declarations. An empty rule such as &{} does not. A border-image or all declaration before a nested rule no longer prevents merging the border longhands after it.
Stop merging rules that have an invalid selector, such as b: hover, [a b], :lang(en fr) or a||b. An invalid selector makes the whole selector list invalid, so the browser also dropped the valid rule it was merged with.
Only treat a dimension as the font size in the font shorthand when it has a length unit. An invalid value such as font:bold 1s "Arial Black" is now left unchanged.
Leave the font shorthand unchanged when it contains attr(), if(), inherit() or a custom function such as --name(), as already done for var() and env(). Their result is only known when the browser computes the value.
Remove a zero color stop position only when it has the right type for the gradient. conic-gradient() now drops 0deg and keeps an invalid 0px, while linear and radial gradients still drop 0px. -webkit-linear-gradient() keeps to bottom and other to directions as written, since the prefixed syntax measures angles differently.
Stop turning a comment inside a selector into a descendant combinator. A comment is not whitespace, so .a/**/.b selects elements with both classes, including inside :is(), and is no longer rewritten as .a .b. Invalid selectors such as div/**/span are left as written instead of becoming valid.
Leave rules with an invalid selector unchanged, including an ID selector that starts with a digit, such as #1a, and a combinator after a pseudo-element, such as a::before b.
Shorten top center and bottom center to top and bottom, instead of 0 and 100%, which the browser reads as horizontal positions. center top and center bottom are now shortened the same way.
Leave a position unchanged when it cannot be safely rewritten:
background layer where another value splits the position, as in left no-repeat center, which is invalid;attr(), if() or a custom --function(), which may return a keyword, as var() already did;left abs(1px) top, as calc() already did.Keep strings unchanged when removing a line continuation (a backslash before a newline) right after an escape. In "\31 followed by a line continuation and 2", joining the lines would turn \31 into \312, so the result is now "\31 2".
Leave @charset unchanged. Browsers only recognize it with double quotes, so rewriting single quotes would make an ignored @charset take effect.
Update postcss-calc to 11.2.2. postcss-calc() now attempts to preserve fractions if the replacement would lose too much precision
place-content, place-items and place-self shorthands, such as align-items:center;justify-items:start into place-items:center start. This only happens when every browser in your Browserslist targets supports the shorthands, because a browser that does not would ignore both alignments. The defaults query includes browsers with unknown support, such as Opera Mini and UC Browser, so it keeps the longhands. Values that use safe, unsafe or last baseline merge only when both values use the same keywords. postcss-merge-longhand now accepts the Browserslist options overrideBrowserslist, stats, path and env.Write numbers in scientific notation when it is shorter, such as 1e-6px for 0.000001px and 1e6px for 1000000px. This also applies when length unit conversion is disabled. Numbers written without a decimal point, such as z-index:1000000, keep their form, because an <integer> cannot use scientific notation.
Stop turning a comment inside a selector into a descendant combinator. A comment is not whitespace, so div/*c*/span is not the same selector as div span. It now becomes div/**/span instead. Comments that can be removed without joining two tokens are still removed, so .a/*c*/.b becomes .a.b.
Stop merging longhands across a nested rule or at-rule. The shorthand ended up after the nested rule and overrode it, so in a{margin-top:1px;&{margin-top:2px}…} the nested margin-top was lost. This applies to margin, padding, border, border-radius and columns. Declarations on each side of a nested rule are now merged separately. An at-rule without a block, such as @apply x;, also separates them, since it may add declarations. An empty rule such as &{} does not. A border-image or all declaration before a nested rule no longer prevents merging the border longhands after it.
Stop merging rules that have an invalid selector, such as b: hover, [a b], :lang(en fr) or a||b. An invalid selector makes the whole selector list invalid, so the browser also dropped the valid rule it was merged with.
Only treat a dimension as the font size in the font shorthand when it has a length unit. An invalid value such as font:bold 1s "Arial Black" is now left unchanged.
Leave the font shorthand unchanged when it contains attr(), if(), inherit() or a custom function such as --name(), as already done for var() and env(). Their result is only known when the browser computes the value.
Remove a zero color stop position only when it has the right type for the gradient. conic-gradient() now drops 0deg and keeps an invalid 0px, while linear and radial gradients still drop 0px. -webkit-linear-gradient() keeps to bottom and other to directions as written, since the prefixed syntax measures angles differently.
Stop turning a comment inside a selector into a descendant combinator. A comment is not whitespace, so .a/**/.b selects elements with both classes, including inside :is(), and is no longer rewritten as .a .b. Invalid selectors such as div/**/span are left as written instead of becoming valid.
Leave rules with an invalid selector unchanged, including an ID selector that starts with a digit, such as #1a, and a combinator after a pseudo-element, such as a::before b.
Shorten top center and bottom center to top and bottom, instead of 0 and 100%, which the browser reads as horizontal positions. center top and center bottom are now shortened the same way.
Leave a position unchanged when it cannot be safely rewritten:
background layer where another value splits the position, as in left no-repeat center, which is invalid;attr(), if() or a custom --function(), which may return a keyword, as var() already did;left abs(1px) top, as calc() already did.Keep strings unchanged when removing a line continuation (a backslash before a newline) right after an escape. In "\31 followed by a line continuation and 2", joining the lines would turn \31 into \312, so the result is now "\31 2".
Leave @charset unchanged. Browsers only recognize it with double quotes, so rewriting single quotes would make an ignored @charset take effect.
Require Browserslist 4.29.3 or later.
Update postcss-calc to 11.2.2. Multiplications inside calc() now keep their original operand order, so calc(var(--x) * 5) is no longer rewritten as calc(5 * var(--x)).
fix: collapse redundant whitespace in at-rules in #1999
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@9.1.1...cssnano@9.1.2
Omit redundant whitespace after @media and @supports when parameters begin with parentheses, and normalize multi-character whitespace after at-rule keywords.
fix: update browserslist
fix(postcss-convert-values): preserve unicode range in #1995
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@9.1.0...cssnano@9.1.1
unicode-range) in font descriptors and custom properties, preventing code point ranges from being corrupted into invalid numbers or dimensions.Merge corner border-*-radius longhands into border-radius shorthands. Four complete corner declarations in the same importance lane now collapse into
border-*-radius longhands into border-radius shorthands. Four complete corner declarations in the same importance lane now collapse into one shorthand, with horizontal and vertical axes minified independently and separated by a slash when distinct.Merge margin, padding, border, border-radius, columns, and border-spacing declarations inside at-rule containers such as @page, @position-try, and nested at-rules. Fold identical horizontal and vertical border-spacing components to a single value. Recognize columns shorthands combining a count and a math function in either order, and preserve invalid declarations as written: border shorthands with multiple styles and columns values combining CSS-wide keywords with widths or counts no longer discard preceding valid longhands.
Preserve percentage units in registered custom-property initial values with composite syntax, ranges, groups, and multipliers, and avoid clamping numeric operands nested inside alpha-value functions.
Restrict color minification to CSS properties that accept <color> and custom properties, preserving custom identifiers in properties like animation-name, grid-area, and counter-reset. Add support for hwb() color values and minification inside color-mix(), light-dark(), and var() fallbacks, while preserving relative color syntax, math functions, and token boundary separators.
Preserve zero percentage units in rgb(), rgba(), and modern CSS Color 4 functions to avoid invalid syntax, respect disabled time conversions for 0ms, clamps percentage opacity values adhering to CSS Color 4 alpha semantics, and improve compatibility with uppercase at-rules and vendor-prefixed keyframes.
Preserves zero length in columns shorthands and zero units inside @property with <angle-percentage> syntax, retaining keyframe percentage units under nested rules. Symmetrically rounds negative numbers when precision is configured, converts between metric units (mm, cm, q), preserves zero percentages on SVG stroke properties to retain transition interpolation, and caches Browserslist lookups across runs. Also preserves units inside CSS Fonts 5 override descriptors, anchor() functions, flex-basis, and IE-targeted sizing properties.
Remove comments more reliably and preserve the ones you keep exactly. Comments are now removed from !important declaration values and comment detection respect CSS token boundaries: text inside unquoted url() values and behind escape sequences in strings and identifiers is no longer mistaken for a comment. Kept comments are emitted byte-for-byte, including an unclosed comment at the end of a value, and whitespace inside kept comments is left untouched. Removal state is scoped to each document, so a shared processor no longer carries removeAllButFirst first-comment state between runs, and the remove callback runs once per comment occurrence. A non-function remove option now fails with a TypeError.
Improve conformance for modern CSS math functions, grid-line values, and case-sensitive attribute selector modifiers while preserving ambiguous or invalid declarations. The affected transforms now use bounded, linear scans for these forms.
Value transforms now read the CSS Values 4 math function names from one mathFunctions table in cssnano-utils, so unit retention, box and shorthand merging, parameter and whitespace handling, and time classification agree on which functions count as math functions. Serialized output is unchanged.
Standardize output normalization for margin, padding, and physical border properties. Property names and case-insensitive keywords in generated shorthands and normalized standalone shorthand declarations are canonicalized to lowercase, while preserving author casing for unmerged longhands, custom properties, hack prefixes, and unresolved values.
perf: median 15% speed increase on test fixtures
postcss-normalize-url now decodes quoted url(...) values, preserving literal backslashes and escape sequences whether quotes are stripped or kept.
Relative URLs now normalize using POSIX path semantics across all platforms, and converted @namespace URLs escape double quotes.
Join every escaped line continuation in a multiline url() value into one line, including \r\n continuations that previously left an invalid string behind. Rewriting a @namespace URL no longer overwrites the tokens that follow it, so trailing text is preserved and multiple URLs in one namespace declaration are each normalized.
Remove insignificant whitespace around custom-property names and, in standard declarations, around env() custom-ident arguments and around comma delimiters in var(), env(), and constant(). Between a custom-property name and its value, only the parser-consumed leading whitespace run is dropped; authored whitespace elsewhere in the value, such as after a preserved comment, is preserved per CSS Variables 2. Required whitespace between distinct tokens and the single whitespace token in an empty fallback remain preserved, and a preserved comment kept between a declaration name and value now survives minification, for custom properties and standard declarations alike. Comment removal in selectors and values no longer fuses the tokens the comment in-between: an attribute case-insensitivity flag or any other name-like token keeps its boundary, and math-operator spacing is restored for every function whose value productions accept <calc-sum> arguments (including calc-size(), calc-mix(), and random()). Values without comments are now left byte-for-byte untouched rather than re-spaced.
Preserve whitespace around division operators across all modern CSS math functions such as min(), max(), and clamp(), and trim extraneous whitespace from commas in nested calculations.
Order columns: 2 auto as columns: auto 2. Leave animation declarations with negative iteration counts unchanged. Reorders border and box-shadow math functions that resolve to a length, such as calc(1px + 1em), and leaves other math unchanged. Passes through unknown box-shadow color functions instead of reordering them.
Merge duplicate @keyframes and @counter-style definitions more conservatively.
Use ASCII case-insensitive matching for CSS names and grammar keywords so Unicode lookalikes are preserved, and restrict CSS whitespace normalization to the CSS whitespace set.
Rename identifiers only when their definition and a reference are in the same stylesheet; leave alone names inside var(), env(), attr(), or a custom property fallback; skip reserved words in the encoder; rename reversed() counters and implicit <area>-start/-end lines with their area.
Preserve Windows drive roots, directory dot references, and leading ./ prefixes when the first relative segment contains a colon. Decode unreserved percent-encoded octets while preserving percent-encoded dots, normalize @import at-rules including nested condition URLs, retain quotes for URLs containing non-printable control characters, avoid unnecessary declaration tokenization, and synchronize raw parameters.
Minify equal shorthand components for two-axis, four-side, alignment, aspect-ratio, and transition declarations while preserving grammar-sensitive and invalid values.
fix(postcss-minify-params): support CSS values level 4 and Media Queries level 5
Preserves invalid selector syntax and namespace-sensitive universal selectors while safely normalizing pseudo-element, View Transition, and keyframe forms. Recognizes the full token grammar for An+B formulas, including escaped forms and exact large integers.
fix(postcss-ordered-values): improve performance and correctness
Aligns SVG data URI processing with WHATWG URL standards by treating the first # as the fragment delimiter. Non-conforming data URLs (such as those with malformed percent-encoding or where an unencoded # in markup truncates the SVG payload) are left untouched rather than parsed with an internal XML recovery scanner. CSS hex escapes in the URI scheme (for example d\61ta:image/svg+xml) reach the optimizer. SVG data URIs inside CSS Values 4 src(...) functions or url(...) declarations with url-modifiers are optimized while preserving modifiers and comments. Minified declarations also keep their raw value metadata in sync.
Unify physical-border optimization under a single reducer that chooses deterministic shortest non-crossing canonical shorthands from complete side and component groups, partitioned by importance lane. Partial grids no longer require a full border reset. Dynamic declarations, style hacks, CSS-wide keywords, support fallbacks, unresolved substitutions, and other cascade barriers remain in their original positions, while valid fallback and border-image behavior is preserved.
Parse font weights and column units from tokenizer metadata. This safely minifies escaped bold weights, recognizes escaped length units, and prevents partial rewrites of invalid font shorthands while preserving original source spelling.
Update browserslist
Preserve matching-importance all reset boundaries when merging margin, padding, physical border-radius, and columns declarations, so minification does not restore values cleared by the reset.
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@9.0.5...cssnano@9.1.0
border-*-radius longhands into border-radius shorthands. Four complete corner declarations in the same importance lane now collapse into one shorthand, with horizontal and vertical axes minified independently and separated by a slash when distinct. Declarations in the radius family are decoupled from physical border fast-path eligibility, allowing rules containing both physical borders and border radii to optimize both families.Merge margin, padding, border, border-radius, columns, and border-spacing declarations inside at-rule containers such as @page, @position-try, and nested at-rules. Fold identical horizontal and vertical border-spacing components to a single value. Recognize columns shorthands combining a count and a math function in either order, and preserve invalid declarations as written: border shorthands with multiple styles and columns values combining CSS-wide keywords with widths or counts no longer discard preceding valid longhands.
Preserves percentage units in registered custom-property initial values with composite syntax, ranges, groups, and multipliers, and avoids clamping numeric operands nested inside alpha-value functions.
Rules with identical selectors now merge without changing which declaration wins the cascade. A rule that repeats a value already overridden inside the earlier rule, or that overrides a later shorthand with a longhand, keeps its declaration instead of being dropped as a duplicate, so the computed styles of merged rules match the original stylesheet.
Declarations whose standard property names differ only in case, such as COLOR and color, now merge like identically spelled properties. Custom property names stay case-sensitive, so --FOO and --foo remain distinct declarations.
Restricts color minification to CSS properties that accept <color> and custom properties, preserving custom identifiers in properties like animation-name, grid-area, and counter-reset. Adds support for hwb() color values and minification inside color-mix(), light-dark(), and var() fallbacks, while preserving relative color syntax, math functions, and token boundary separators.
Preserves zero percentage units in rgb(), rgba(), and modern CSS Color 4 functions to avoid invalid syntax, respects disabled time conversions for 0ms, clamps percentage opacity values adhering to CSS Color 4 alpha semantics, and improves compatibility with uppercase at-rules and vendor-prefixed keyframes.
Preserves zero length in columns shorthands and zero units inside @property with <angle-percentage> syntax, retaining keyframe percentage units under nested rules. Symmetrically rounds negative numbers when precision is configured, converts between metric units (mm, cm, q), preserves zero percentages on SVG stroke properties to retain transition interpolation, and caches Browserslist lookups across runs. Also preserves units inside CSS Fonts 5 override descriptors, anchor() functions, flex-basis, and IE-targeted sizing properties.
Remove comments more reliably and preserve the ones you keep exactly. Comments are now removed from declaration values that carry !important, and comment detection respects CSS token boundaries: text inside unquoted url() values and behind escape sequences in strings and identifiers is no longer mistaken for a comment. Kept comments are emitted byte-for-byte, including an unclosed comment at the end of a value, and whitespace inside kept comments is left untouched. Removal state is scoped to each document, so a shared processor no longer carries removeAllButFirst first-comment state between runs, and the remove callback runs once per comment occurrence. A non-function remove option now fails with a TypeError.
Folds more selector lists into safe :is() expressions when their selectors contain nested comma-separated functions, while preserving selector order and conservative specificity and namespace checks.
Recognizes currentColor and system colours such as canvas as colour stops, so their positions are clamped or dropped like any other stop. A stop position at or below the running non-negative maximum is now written as zero even when the two positions use different units, and minifying an already minified gradient no longer changes it again. Single-stop gradients lose positions that spell the default boundaries. Positions are no longer replaced with zero when the largest position is negative.
Adds the balanced token index used by selector, parameter, and gradient minification while preserving their serialized CSS output.
Improve conformance for modern CSS math functions, grid-line values, and case-sensitive attribute selector modifiers while preserving ambiguous or invalid declarations. The affected transforms now use bounded, linear scans for these forms.
Value transforms now read the CSS Values 4 math function names from one mathFunctions table in cssnano-utils, so unit retention, box and shorthand merging, parameter and whitespace handling, and time classification agree on which functions count as math functions. Serialized output is unchanged.
Standardize output normalization for margin, padding, and physical border properties. Property names and case-insensitive keywords in generated shorthands and normalized standalone shorthand declarations are canonicalized to lowercase, while preserving author casing for unmerged longhands, custom properties, hack prefixes, and unresolved values.
Merge rules that use modern pseudo-classes and pseudo-elements — :modal, ::file-selector-button, :read-only, :read-write, :autofill, and :fullscreen — when every browser in the target list supports the corresponding feature. Support is still checked per browser, so these selectors remain unmerged under older targets, and pseudos without verified support data such as :popover-open and :user-invalid continue to block merging.
perf: median 15% speed increase on test fixtures
postcss-normalize-url now decodes quoted url(...) values, preserving literal backslashes and escape sequences whether quotes are stripped or kept.
Relative URLs now normalize using POSIX path semantics across all platforms, and converted @namespace URLs escape double quotes.
Join every escaped line continuation in a multiline url() value into one line, including \r\n continuations that previously survived and left an invalid string behind. Rewriting a @namespace URL no longer overwrites the tokens that follow it, so trailing text is preserved and multiple URLs in one namespace declaration are each normalized.
Remove insignificant whitespace around custom-property names and, in standard declarations, around env() custom-ident arguments and around comma delimiters in var(), env(), and constant(). Between a custom-property name and its value, only the parser-consumed leading whitespace run is dropped; authored whitespace elsewhere in the value, such as after a preserved comment, is preserved per CSS Variables 1. Required whitespace between distinct tokens and the single whitespace token in an empty fallback remain preserved, and a preserved comment kept between a declaration name and value now survives minification, for custom properties and standard declarations alike. Comment removal in selectors and values no longer fuses the tokens the comment sat between: an attribute case-insensitivity flag or any other name-like token keeps its boundary, and math-operator spacing is restored for every function whose value productions accept <calc-sum> arguments (including calc-size(), calc-mix(), and random()). Values without comments are now left byte-for-byte untouched rather than re-spaced.
Preserve whitespace around division operators across all modern CSS math functions such as min(), max(), and clamp(), and ensure commas in nested calculations have extraneous whitespace trimmed.
Orders columns: 2 auto as columns: auto 2. Leaves animation declarations with negative iteration counts unchanged. Reorders border and box-shadow math functions that resolve to a length, such as calc(1px + 1em), and leaves other math unchanged. Passes through unknown box-shadow color functions instead of reordering them.
Profitable adjacent rule merges are no longer skipped by the legacy look-ahead, and important comments are preserved when equal-declaration rules are merged.
Normalize CSS string quotes and collapse escaped line continuations.
Use ASCII case-insensitive matching for CSS names and grammar keywords so Unicode lookalikes are preserved, and restrict CSS whitespace normalization to the CSS whitespace set.
Only reduce transform functions whose component types match the spec; keep invalid values unchanged. Never merge a var() reference with an env() reference of the same name.
Preserve Windows drive roots, directory dot references, and leading ./ prefixes when the first relative segment contains a colon. Decode unreserved percent-encoded octets while preserving percent-encoded dots, normalize @import at-rules including nested condition URLs, retain quotes for URLs containing non-printable control characters, avoid unnecessary declaration tokenization, and synchronize raw parameters.
Minify equal shorthand components for two-axis, four-side, alignment, aspect-ratio, and transition declarations while preserving grammar-sensitive and invalid values.
fix(postcss-minify-params): support CSS values level 4 and Media Queries level 5
Preserves invalid selector syntax and namespace-sensitive universal selectors while safely normalizing pseudo-element, View Transition, and keyframe forms. Recognizes the full token grammar for An+B formulas, including escaped forms and exact large integers.
fix(postcss-ordered-values): improve performance and correctness
Aligns SVG data URI processing with WHATWG URL standards by treating the first # as the fragment delimiter. Non-conforming data URLs (such as those with malformed percent-encoding or where an unencoded # in markup truncates the SVG payload) are left untouched rather than parsed with an internal XML recovery scanner. CSS hex escapes in the URI scheme (for example d\61ta:image/svg+xml) reach the optimizer. SVG data URIs inside CSS Values 4 src(...) functions or url(...) declarations with url-modifiers are optimized while preserving modifiers and comments. Minified declarations also keep their raw value metadata in sync.
Unify physical-border optimization under a single reducer that chooses deterministic shortest non-crossing canonical shorthands from complete side and component groups, partitioned by importance lane. Partial grids no longer require a full border reset. Dynamic declarations, style hacks, CSS-wide keywords, support fallbacks, unresolved substitutions, and other cascade barriers remain in their original positions, while valid fallback and border-image behavior is preserved.
Parse font weights and column units from tokenizer metadata. This safely minifies escaped bold weights, recognizes escaped length units, and prevents partial rewrites of invalid font shorthands while preserving original source spelling.
update browserslist
Preserve matching-importance all reset boundaries when merging margin, padding, physical border-radius, and columns declarations, so minification does not restore values cleared by the reset.
Updated dependencies:
fix(postcss-svgo): decode SVG following WHATWG specification in #1975
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@9.0.4...cssnano@9.0.5
fix: updae browserslist, mdn-data, autoprefixer
fix(postcss-svgo): better decode encoded SVG
fix: update postcss-calc
fix: update calc and color minifiers, autoprefixer
fix: update postcss-calc in #1970
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@9.0.3...cssnano@9.0.4
fix: update color parsing library in #1964
fix: update color parsing library in #1964
fix: update PostCSS and selector parser
fix: update conflict detection and color conversion CSS spec conformance
fix: update PostCSS peer dependency
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@9.0.2...cssnano@9.0.3
fix(postcss-colormin, postcss-minify-gradients): update color parsing library
fix: update postcss and selector parser
fix: update conflict detection and color conversion CSS spec conformance
fix: update PostCSS peer dependency
fix: add main and types to package manifests in #1958
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@9.0.1...cssnano@9.0.2
fix: ensure older tools can resolve cssnano packages
fix(cssnano-preset-default): update postcss-calc
refactor: some small performance gains in #1955
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@9.0.0...cssnano@9.0.1
perf(postcss-minify-selectors): avoid quadratic selector scanning
pef(stylehacks): avoid rescanning the nodes when checking for compatibility hacks
Migrate to ESM and simplify config loading in #1948
Probably backward-compatible for most users. Some changes to configuration loading documented in migration guide.
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@8.0.10...cssnano@9.0.0
The cssnano packages are now native ESM and require Node ^22.22.3 || ^24.15.0 || >=26.0. Package subpath imports are no longer supported. See the migration documentation before upgrading.
fix!(cssnano): introduce new postcss-calc plugin
Make charset normalization idempotent in #1949
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@8.0.9...cssnano@8.0.10
Bug fixes coming by way of updating colordx and svgo to the latest release.
Bug fixes coming by way of updating colordx and svgo to the latest release.
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@8.0.8...cssnano@8.0.9
fix(postcss-minify-gradients): minify gradients using spec algorithm in #1941
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@8.0.7...cssnano@8.0.8
fix(cssnano): tighten option types in #1919
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@8.0.6...cssnano@8.0.7
fix(postcss-ordered-values): recognise easing functions
fix(postcss-reduce-initial): update MDN data
perf(postcss-merge-rules): cache negative browser-support results when deciding whether to merge rules
Checking whether a selector feature is supported by the target browsers previously skipped the cache whenever the feature was not supported, so every occurrence of an unsupported feature re-ran the browserslist/caniuse lookup. This is now cached, which speeds up rule merging.
fix(postcss-discard-empty): remove empty cascade layers when they do not affect the layer ordering
fix(postcss-normalize-whitespace): stop dropping the escaped character in a trailing backslash escape
Keep the whitespace character when a declaration ends in a backslash character followed by a whitespace character and the declaration is the last in its rule, instead of leaving a dangling character and invalid CSS
fix(postcss-merge-rules): fix invalid merging in #1893
fix(postcss-merge-rules): fix invalid merging in #1893
fix(postcss-merge-rules): use webref data to perform a merge #1897
fix(postcss-reduce-idents): do not break grid-template-areas in #1898
fix: ensure correct repository URL in published packages in #1900
fix(postcss-merge-longhand): improve longhand merging correctness in #1907
fix(postcss-merge-longhand): add a fuzzer and fix the cases it found in #1914
fix: improve selector minification in #1915
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@8.0.5...cssnano@8.0.6
fix(postcss-merge-rules): keep the cascade intact when hoisting declarations
fix(postcss-merge-rules): decide property conflicts from spec data
The plugin decides whether to reorder declarations using @webref/css data instead of a name-based heuristic. For example, the plugin now recognizes that font and line-height, border-width and border-left, gap and row-gap, and inset and top conflict, and that a flow-relative property and its physical counterpart override each other.
The plugin now merges properties that do not override each other, but only share part of the name, such as flexandflex-direction`. Vendor extensions that are not part of a W3C specification still fall back to comparing names.
fix(postcss-merge-longhand): improve shorthand merging correctness
Reject merges producing invalid values for border, margin, or padding; do not confuse math functions with border styles or colors; preserve fallback declarations before functions like env() or calc(); correctly weight !important; and stop resurrecting declarations overridden elsewhere.
fix: ensure packages reach registry with correct repository field
fix(postcss-merge-rules): merge interleaved declarations correctly
fix(postcss-reduce-idents): rewrite identifiers based on spec data
Which declarations define and reference a custom identifier now comes from @webref/css instead of matching property names against a substring. The plugin no longer leaves a renamed identifier dangling behind:
@counter-style renamed while another rule's fallback descriptor, or a counter()/counters()/target-counter() argument, still names it by its old namegrid shorthand, which was never rewritten even though the grid-area placing against it wasrepeat() or minmax()string-set propertyIt also no longer renames a keyframe name appearing where it is not allowed, such as animation-timing-function, and only renames the argument of a counter function that names a counter, rather than every word inside it.
Identifiers identical to a keyword of the property or descriptor, such as an animation called linear, a counter style called inside, or the words of speak-as: words, are now left alone: which of the two a value means depends on the order the grammar is matched in, so renaming it was unsafe.
The counters the user agent maintains itself, list-item and page, are no longer renamed either.
fix(postcss-merge-longhand): fix issues with border merging in #1886
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@8.0.4...cssnano@8.0.5
fix(postcss-merge-longhand): avoid merging border declarations when result is not equivalent
fix: update dependencies
Fix postcs-svgo encoding in #1877
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@8.0.3...cssnano@8.0.4
fix(postcss-svgo): encode chracters in the correct order
fix(postcss-svgo): do not roll our own URI encoding
Our own code, while producing smaller output, might end up producing the wrong encoding, since it does not encode all characters.
postcss-reduce-initial: update initial properties
packages now define an exports field in package.json. This prevents any file added to the package to automatically be exposed as a possible import. The has been done in a backward compatible way, so you should be able to import every file you did in the previous release.
types have also been regenerated with TypeScript 7.
Full Changelog: https://github.com/cssnano/cssnano/compare/cssnano@8.0.2...cssnano@8.0.3
fix(postcss-normalize-url): add missing TypeScript files
chore: regenerate all type definitions with TypeScript 7
fix: update svgo, autoprefixer and postcss
fix: update PostCSS
chore: define package.json exports
chore: update dependencies
Update autoprefixer, browserslist, colordx and postcss
chore: update the postcss peer dependency
fix(postcss-minify-selectors): avoid folding some selectors incorrectly
ea8e33a: chore: drop Node.js 20 support
ea8e33a: chore: drop Node.js 20 support
Node.js 20 has reached end of life.
d7c57da: Removed cssDeclarationSorter from the default preset. It remains enabled in
the advanced preset.
The plugin can cause breakages without notice whenever a new CSS longhand property is released to browsers if it happens to cause a conflict with another longhand property. To ensure safety and predictability, it is no longer enabled by default.
If you rely on declaration sorting, you can switch to the advanced preset or
explicitly enable cssDeclarationSorter in your configuration.
fix(postcss-minify-selectors): do not fold non-standard selectors
0005443: fix(postcss-minify-selectors): fix wrong behaviour when merging into is()
fix: publish all dependencies with attestations
322ad33: fix: update postcss peer dependency
5cb8b09: fix: udpate browserslist
fix: improve color conversion precision
c3e537a: fix: update postcss-selector-parser
72dd9c9: fix: update browserslist
fix: do not strip % sign inside linear()
906a785: fix: update browserslist
5672148: fix: update PostCSS peer dependency to version without vulnerabilities
024ddef: fix(cssnano-preset-default): update postcss-calc
dff5c42: chore: update browserslist and postcss-selector-parser
### Patch Changes - Updated dependencies [d6f9a32] - postcss-convert-values@7.0.2
0c85fa9: fix: update Browserslist version
### Patch Changes - Updated dependencies [c14b9f5] - Updated dependencies [759e16e] - postcss-minify-selectors@7.0.1 - postcss-unique-selectors@7.0.1
2a26e29: chore: update postcss-calc to latest release
0d10597: chore: drop support for Node.js 14 and 16
fix(cssnano-preset-default): update css-declaration-sorter
postcss-minify-font-values@6.1.0
feat: add preset and plugin options for browserslist
postcss-minify-font-values@6.0.2
postcss-discard-duplicates@6.0.2
9c6b0bc: fix(cssnano-preset-default): do not sort unknown properties
18331a6: fix: update cssnano peer dependency to 8.4.31 to avoid security issue
chore: updage postcss-calc to version 9
ca9d3f55: chore: bump node versions for packages depending on svgo
fix(postcsss-reduce-initial): fix mask-repeat conversion fix(postcss-colormin): don't minify colors in src declarations fix(postcss-merge-rules): do n
fix: update autoprefixer and browserslist
fix: preserve hyphenated property case
### Patch Changes - fix: preserve constant values - Updated dependencies - postcss-ordered-values@5.1.2
chore: update TypeScript and improve types
fix: preserve more color function fallbacks
postcss-convert-values: preserve percentage sign on IE 11
fix: update postcss-merge-longhand. It was skipped by mistake in the previous release.
fix: preserve border color when merging border properties
fix: correct package.json dependency version specifier
Your coding agent can read these notes before it upgrades. Set up the MCP server →