From 478e9590971b5ca0800f7d3a9ecc92e655fe6659 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 8 Dec 2025 09:40:16 -0500 Subject: [PATCH] =?UTF-8?q?Don=E2=80=99t=20emit=20color-mix=20fallback=20r?= =?UTF-8?q?ules=20inside=20`@keyframes`=20(#19419)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #19417 --- CHANGELOG.md | 1 + packages/tailwindcss/src/ast.test.ts | 30 ++++++++++++++++++++++++++++ packages/tailwindcss/src/ast.ts | 11 +++++++--- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 035b39c69..a62747d10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Validate candidates similarly to Oxide ([#19397](https://github.com/tailwindlabs/tailwindcss/pull/19397)) - Canonicalization: combine `text-*` and `leading-*` classes ([#19396](https://github.com/tailwindlabs/tailwindcss/pull/19396)) - Correctly handle duplicate CLI arguments ([#19416](https://github.com/tailwindlabs/tailwindcss/pull/19416)) +- Don’t emit color-mix fallback rules inside `@keyframes` ([#19419](https://github.com/tailwindlabs/tailwindcss/pull/19419)) ### Added diff --git a/packages/tailwindcss/src/ast.test.ts b/packages/tailwindcss/src/ast.test.ts index 63a621c6a..24f31f7bb 100644 --- a/packages/tailwindcss/src/ast.test.ts +++ b/packages/tailwindcss/src/ast.test.ts @@ -290,6 +290,36 @@ it('should not emit exact duplicate declarations in the same rule', () => { `) }) +it('should not emit color-mix() fallbacks inside @keyframes', () => { + let ast = CSS.parse(css` + @keyframes my-animation { + 0% { + color: color-mix(in oklab, var(--color-emerald-600) 0%, transparent); + } + 100% { + color: color-mix(in oklab, var(--color-emerald-600) 0%, transparent); + } + } + `) + + let theme = new Theme() + theme.add('--color-emerald-600', 'oklch(59.6% 0.145 163.225)') + + let design = buildDesignSystem(theme) + + expect(toCss(optimizeAst(ast, design))).toMatchInlineSnapshot(` + "@keyframes my-animation { + 0% { + color: color-mix(in oklab, var(--color-emerald-600) 0%, transparent); + } + 100% { + color: color-mix(in oklab, var(--color-emerald-600) 0%, transparent); + } + } + " + `) +}) + it('should only visit children once when calling `replaceWith` with single element array', () => { let visited = new Set() diff --git a/packages/tailwindcss/src/ast.ts b/packages/tailwindcss/src/ast.ts index 4069268c1..ab0a4fb4d 100644 --- a/packages/tailwindcss/src/ast.ts +++ b/packages/tailwindcss/src/ast.ts @@ -275,13 +275,18 @@ export function optimizeAst( // Track used animation names if (node.property === 'animation') { - for (let keyframeName of extractKeyframeNames(node.value)) + for (let keyframeName of extractKeyframeNames(node.value)) { usedKeyframeNames.add(keyframeName) + } } // Create fallback values for usages of the `color-mix(…)` function that reference variables - // found in the theme config. - if (polyfills & Polyfills.ColorMix && node.value.includes('color-mix(')) { + // found in the theme config. + if ( + polyfills & Polyfills.ColorMix && + node.value.includes('color-mix(') && + !context.keyframes + ) { colorMixDeclarations.get(parent).add(node) }