From f240d2ddd547e2a980132605a599d83880424b0e Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 29 Sep 2025 16:02:50 -0400 Subject: [PATCH 1/2] Remove irrelevant utility rules when matching important classes --- src/lib/generateRules.js | 9 ++- tests/custom-plugins.test.js | 149 +++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index 12690e5e6eae..ba2e3055720f 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -143,7 +143,14 @@ function applyImportant(matches, classCandidate) { className === classCandidate ? `!${className}` : className ) - r.selector = ast.toString() + let newSelector = ast.toString() + + if (newSelector.trim() === '') { + r.remove() + return + } + + r.selector = newSelector r.walkDecls((d) => (d.important = true)) }) diff --git a/tests/custom-plugins.test.js b/tests/custom-plugins.test.js index d1ae598e5efb..a5176441b5aa 100644 --- a/tests/custom-plugins.test.js +++ b/tests/custom-plugins.test.js @@ -1914,3 +1914,152 @@ test('custom properties are not converted to kebab-case when added to base layer expect(result.css).toContain(`--colors-primaryThing-500: 0, 0, 255;`) }) }) + +test('important candidates discard rules with irrelevant selectors', async () => { + let config = { + content: [{ raw: '!a1 !b1 !c1' }], + corePlugins: { preflight: false }, + plugins: [ + ({ addBase }) => { + addBase({ + '@media (min-width: 1728px)': { + '.a1': { 'padding-top': '1rem !important' }, + '.a2': { 'padding-right': '1rem !important' }, + }, + }) + + addBase({ + '@media (min-width: 1728px)': { '.b1': { 'padding-top': '1rem !important' } }, + '@media (min-width: 1729px)': { '.b2': { 'padding-right': '1rem !important' } }, + }) + + addBase({ + '.c1': { '@media (min-width: 1728px)': { 'padding-top': '1rem !important' } }, + '.c2': { '@media (min-width: 1728px)': { 'padding-right': '1rem !important' } }, + }) + }, + ], + } + + let result = await run('@tailwind base', config) + + expect(result.css).toMatchInlineSnapshot(` + "*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: + } + ::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + --tw-contain-size: ; + --tw-contain-layout: ; + --tw-contain-paint: ; + --tw-contain-style: + } + @media (min-width: 1728px) { + .\\!a1 { + padding-top: 1rem !important + } + .\\!b1 { + padding-top: 1rem !important + } + .\\!c1 { + padding-top: 1rem !important + } + }" + `) +}) From da2a5f064b8916460186dc9fcccfe76884497249 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 29 Sep 2025 16:05:58 -0400 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92f03b87c085..f9af15ba297d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix `require.cache` error when loaded through a TypeScript file in Node 22.18+ ([#18665](https://github.com/tailwindlabs/tailwindcss/pull/18665)) - Support `import.meta.resolve(…)` in configs for new enough Node.js versions ([#18938](https://github.com/tailwindlabs/tailwindcss/pull/18938)) - Allow using newer versions of `postcss-load-config` for better ESM and TypeScript PostCSS config support with the CLI ([#18938](https://github.com/tailwindlabs/tailwindcss/pull/18938)) +- Remove irrelevant utility rules when matching important classes ([#19030](https://github.com/tailwindlabs/tailwindcss/pull/19030)) ## [3.4.17] - 2024-12-17