tailwindcss/packages/@tailwindcss-postcss/src/index.test.ts

351 lines
8.6 KiB
TypeScript
Raw Normal View History

import dedent from 'dedent'
2024-03-05 14:23:26 +01:00
import { unlink, writeFile } from 'node:fs/promises'
import postcss from 'postcss'
import { afterEach, beforeEach, describe, expect, test } from 'vitest'
import tailwindcss from './index'
// We give this file path to PostCSS for processing.
// This file doesn't exist, but the path is used to resolve imports.
// We place it in packages/ because Vitest runs in the monorepo root,
// and packages/tailwindcss must be a sub-folder for
// @import 'tailwindcss' to work.
function inputCssFilePath() {
// Including the current test name to ensure that the cache is invalidated per
// test otherwise the cache will be used across tests.
return `${__dirname}/fixtures/example-project/input.css?test=${expect.getState().currentTestName}`
}
2024-03-05 14:23:26 +01:00
const css = dedent
2024-03-05 14:23:26 +01:00
test("`@import 'tailwindcss'` is replaced with the generated CSS", async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
])
2024-03-05 14:23:26 +01:00
let result = await processor.process(`@import 'tailwindcss'`, { from: inputCssFilePath() })
2024-03-05 14:23:26 +01:00
expect(result.css.trim()).toMatchSnapshot()
// Check for dependency messages
expect(result.messages).toContainEqual({
type: 'dependency',
file: expect.stringMatching(/index.html$/g),
parent: expect.any(String),
plugin: expect.any(String),
})
expect(result.messages).toContainEqual({
type: 'dependency',
file: expect.stringMatching(/index.js$/g),
parent: expect.any(String),
plugin: expect.any(String),
})
expect(result.messages).toContainEqual({
type: 'dir-dependency',
dir: expect.stringMatching(/example-project[\/|\\]src$/g),
2024-03-05 14:23:26 +01:00
glob: expect.stringMatching(/^\*\*\/\*/g),
parent: expect.any(String),
plugin: expect.any(String),
})
})
test('output is optimized by Lightning CSS', async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
])
2024-03-05 14:23:26 +01:00
let result = await processor.process(
css`
@layer utilities {
.foo {
@apply text-[black];
}
}
@layer utilities {
.bar {
color: red;
}
}
`,
{ from: inputCssFilePath() },
2024-03-05 14:23:26 +01:00
)
expect(result.css.trim()).toMatchInlineSnapshot(`
"@layer utilities {
.foo {
color: #000;
}
.bar {
color: red;
}
}"
`)
})
test('@apply can be used without emitting the theme in the CSS file', async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
])
2024-03-05 14:23:26 +01:00
let result = await processor.process(
css`
Add support for `inline` option when defining `@theme` values (#14095) This PR adds support for a new `inline` option when defining a `@theme` block that tells Tailwind to use raw theme values for utilities instead of referencing the corresponding generated CSS variable. ```css /* Input */ @theme inline { --color-red-500: #ef4444; /* ... */ } /* Example output */ :root { --color-red-500: #ef4444; } .text-red-500 { color: #ef4444; } ``` This can be composed with the existing `reference` option in case you want to define a `@theme` block as both `reference` (so the variables aren't generated) and `inline`: ```css /* Input */ @theme inline reference { --color-red-500: #ef4444; /* ... */ } /* Example output */ .text-red-500 { color: #ef4444; } ``` Since you can have multiple `@theme` blocks, you can even define some values normally and some as inline based on how you're using them. For example you might want to use `inline` for defining literal tokens like `--color-red-500`, but include the variable for tokens that you want to be able to theme like `--color-primary`: ```css /* Input */ @theme inline { --color-red-500: #ef4444; /* ... */ } @theme { --color-primary: var(--color-red-500); } /* Example output */ :root { --color-red-500: #ef4444; --color-primary: var(--color-red-500); } .text-red-500 { color: #ef4444; } .text-primary { color: var(--color-primary, var(--color-red-500)); } ``` ## Breaking changes Prior to this PR, you could `@import` a stylesheet that contained `@theme` blocks as reference by adding the `reference` keyword to your import: ```css @import "./my-theme.css" reference; ``` Now that `reference` isn't the only possible option when declaring your `@theme`, this syntax has changed to a new `theme(…)` function that accepts `reference` and `inline` as potential space-separated values: ```css @import "./my-theme.css"; @import "./my-theme.css" theme(reference); @import "./my-theme.css" theme(inline); @import "./my-theme.css" theme(reference inline); ``` If you are using the `@import … reference` option with an earlier alpha release, you'll need to update your code to `@import … theme(reference)` once this PR lands in a release. ## Motivation This PR is designed to solve an issue pointed out in #14091. Prior to this PR, generated utilities would always reference variables directly, with the raw value as a fallback: ```css /* Input */ @theme { --color-red-500: #ef4444; /* ... */ } /* Example output */ :root { --color-red-500: #ef4444; } .text-red-500 { color: var(--color-red-500, #ef4444); } ``` But this can create issues with variables resolving to an unexpected value when a theme value is referencing another variable defined on `:root`. For example, say you have a CSS file like this: ```css :root, .light { --text-fg: #000; } .dark { --text-fg: #fff; } @theme { --color-fg: var(--text-fg); } ``` Without `@theme inline`, we'd generate this output if you used the `text-fg` utility: ```css :root, .light { --text-fg: #000; } .dark { --text-fg: #fff; } :root { --color-fg: var(--text-fg); } .text-fg { color: var(--color-fg, var(--text-fg)); } ``` Now if you wrote this HTML, you're probably expecting your text to be the dark mode color: ```html <div class="dark"> <h1 class="text-fg">Hello world</h1> </div> ``` But you'd actually get the light mode color because of this rule: ```css :root { --color-fg: var(--text-fg); } .text-fg { color: var(--color-fg, var(--text-fg)); } ``` The browser will try to resolve the `--color-fg` variable, which is defined on `:root`. When it tries to resolve the value, _it uses the value of `var(--text-fg)` as it would resolve at `:root`_, not what it would resolve to based on the element that has the `text-fg` class. So `var(--color-fg)` resolves to `#000` because `var(--text-fg)` resolved to `#000` at the point in the tree where the browser resolved the value of `var(--color-fg)`. By using `@theme inline`, the `.text-fg` class looks like this: ```css .text-fg { color: var(--text-fg); } ``` With this definition, the browser doesn't try to resolve `--color-fg` at all and instead resolves `--text-fg` directly which correctly resolves to `#fff` as expected. --------- Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com> Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-08-02 09:37:30 -04:00
@import 'tailwindcss/theme.css' theme(reference);
2024-03-05 14:23:26 +01:00
.foo {
@apply text-red-500;
}
`,
{ from: inputCssFilePath() },
2024-03-05 14:23:26 +01:00
)
expect(result.css.trim()).toMatchInlineSnapshot(`
".foo {
color: var(--color-red-500);
2024-03-05 14:23:26 +01:00
}"
`)
})
describe('processing without specifying a base path', () => {
let filepath = `${process.cwd()}/my-test-file.html`
beforeEach(() =>
writeFile(filepath, `<div class="md:[&:hover]:content-['testing_default_base_path']">`),
)
afterEach(() => unlink(filepath))
test('the current working directory is used by default', async () => {
let processor = postcss([tailwindcss({ optimize: { minify: false } })])
2024-03-05 14:23:26 +01:00
let result = await processor.process(`@import "tailwindcss"`, { from: inputCssFilePath() })
2024-03-05 14:23:26 +01:00
expect(result.css).toContain(
".md\\:\\[\\&\\:hover\\]\\:content-\\[\\'testing_default_base_path\\'\\]",
)
expect(result.messages).toContainEqual({
type: 'dependency',
file: expect.stringMatching(/my-test-file.html$/g),
parent: expect.any(String),
plugin: expect.any(String),
})
})
})
describe('plugins', () => {
test('local CJS plugin', async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
])
let result = await processor.process(
css`
@import 'tailwindcss/utilities';
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
@plugin './plugin.js';
`,
{ from: inputCssFilePath() },
)
expect(result.css.trim()).toMatchInlineSnapshot(`
".underline {
Add `@source` support (#14078) This PR is an umbrella PR where we will add support for the new `@source` directive. This will allow you to add explicit content glob patterns if you want to look for Tailwind classes in other files that are not automatically detected yet. Right now this is an addition to the existing auto content detection that is automatically enabled in the `@tailwindcss/postcss` and `@tailwindcss/cli` packages. The `@tailwindcss/vite` package doesn't use the auto content detection, but uses the module graph instead. From an API perspective there is not a lot going on. There are only a few things that you have to know when using the `@source` directive, and you probably already know the rules: 1. You can use multiple `@source` directives if you want. 2. The `@source` accepts a glob pattern so that you can match multiple files at once 3. The pattern is relative to the current file you are in 4. The pattern includes all files it is matching, even git ignored files 1. The motivation for this is so that you can explicitly point to a `node_modules` folder if you want to look at `node_modules` for whatever reason. 6. Right now we don't support negative globs (starting with a `!`) yet, that will be available in the near future. Usage example: ```css /* ./src/input.css */ @import "tailwindcss"; @source "../laravel/resources/views/**/*.blade.php"; @source "../../packages/monorepo-package/**/*.js"; ``` It looks like the PR introduced a lot of changes, but this is a side effect of all the other plumbing work we had to do to make this work. For example: 1. We added dedicated integration tests that run on Linux and Windows in CI (just to make sure that all the `path` logic is correct) 2. We Have to make sure that the glob patterns are always correct even if you are using `@import` in your CSS and use `@source` in an imported file. This is because we receive the flattened CSS contents where all `@import`s are inlined. 3. We have to make sure that we also listen for changes in the files that match any of these patterns and trigger a rebuild. PRs: - [x] https://github.com/tailwindlabs/tailwindcss/pull/14063 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14085 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14079 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14067 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14076 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14080 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14127 - [x] https://github.com/tailwindlabs/tailwindcss/pull/14135 Once all the PRs are merged, then this umbrella PR can be merged. > [!IMPORTANT] > Make sure to merge this without rebasing such that each individual PR ends up on the main branch. --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com> Co-authored-by: Jordan Pittman <jordan@cryptica.me> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-08-07 16:38:44 +02:00
text-decoration-line: underline;
}
@media (inverted-colors: inverted) {
.inverted\\:flex {
display: flex;
}
}
.hocus\\:underline:focus, .hocus\\:underline:hover {
text-decoration-line: underline;
}"
`)
})
test('local CJS plugin from `@import`-ed file', async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
])
let result = await processor.process(
css`
@import 'tailwindcss/utilities';
@import '../example-project/src/relative-import.css';
`,
{ from: `${__dirname}/fixtures/another-project/input.css` },
)
expect(result.css.trim()).toMatchInlineSnapshot(`
".underline {
text-decoration-line: underline;
}
@media (inverted-colors: inverted) {
.inverted\\:flex {
display: flex;
}
}
.hocus\\:underline:focus, .hocus\\:underline:hover {
text-decoration-line: underline;
}"
`)
})
test('published CJS plugin', async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
])
let result = await processor.process(
css`
@import 'tailwindcss/utilities';
@plugin 'internal-example-plugin';
`,
{ from: inputCssFilePath() },
)
expect(result.css.trim()).toMatchInlineSnapshot(`
".underline {
text-decoration-line: underline;
}
@media (inverted-colors: inverted) {
.inverted\\:flex {
display: flex;
}
}
.hocus\\:underline:focus, .hocus\\:underline:hover {
text-decoration-line: underline;
}"
`)
})
})
test('bail early when Tailwind is not used', async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
])
let result = await processor.process(
css`
.custom-css {
color: red;
}
`,
{ from: inputCssFilePath() },
)
// `fixtures/example-project` includes an `underline` candidate. But since we
// didn't use `@tailwind utilities` we didn't scan for utilities.
expect(result.css).not.toContain('.underline {')
expect(result.css.trim()).toMatchInlineSnapshot(`
".custom-css {
color: red;
}"
`)
})
test('handle CSS when only using a `@reference` (we should not bail early)', async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
])
let result = await processor.process(
css`
@reference "tailwindcss/theme.css";
.foo {
@variant md {
bar: baz;
}
}
`,
{ from: inputCssFilePath() },
)
expect(result.css.trim()).toMatchInlineSnapshot(`
"@media (width >= 48rem) {
.foo {
bar: baz;
}
}"
`)
})
test('handle CSS when using a `@variant` using variants that do not rely on the `@theme`', async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
])
let result = await processor.process(
css`
.foo {
@variant data-is-hoverable {
bar: baz;
}
}
`,
{ from: inputCssFilePath() },
)
expect(result.css.trim()).toMatchInlineSnapshot(`
".foo[data-is-hoverable] {
bar: baz;
}"
`)
})
test('runs `Once` plugins in the right order', async () => {
let before = ''
let after = ''
let processor = postcss([
{
postcssPlugin: 'before',
Once(root) {
before = root.toString()
},
},
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
{
postcssPlugin: 'after',
Once(root) {
after = root.toString()
},
},
])
let result = await processor.process(
css`
@theme {
--color-red-500: red;
}
.custom-css {
color: theme(--color-red-500);
}
`,
{ from: inputCssFilePath() },
)
expect(result.css.trim()).toMatchInlineSnapshot(`
Only expose used CSS variables (#16211) This PR only exposes used CSS variables. My initial approach was to track the used variables, this was a bit messy because it meant that we had to walk part of the AST(s) in multiple places. We also had to be careful because sometimes if a variable exists in an AST, that doesn't mean that it's actually used. E.g.: ```css h1 { color: var(--color-red-500); /* Definitely used, so let's keep it */ } @utility foo { color: var(--color-blue-500); /* Hmm, used? */ } ``` In this last case, the `--color-blue-500` is part of the CSS AST, but as long as `foo` the utility is not used, it won't end up in your actual CSS file, therefore the variable is **not** used. Alternatively, if the `foo` utility is used with an invalid variant (e.g.: `group-[>.foo]:foo`, then the `@utility foo` code will still run internally because variants are applied on top of the utility. This means that it looks like `var(--color-blue-500)` is being used. Another annoying side effect was that because variables are conditionally generated, that the `@theme` -> `:root, :host` conversion had to happen for every build, instead of once in the `compile(…)` step. --- To prevent all the messy rules and additional booking while walking of ASTs I thought about a different approach. We are only interested in variables that are actually used. The only way we know for sure, is right before the `toCss(…)` step. Any step before that could still throw away AST nodes. However, we do have an `optimizeAst` step right before printing to simplify and optimize the AST. So the idea was to keep all the CSS variables in the AST, and only in the `optimizeAst` step we perform a kind of mark-and-sweep algorithm where we can first check which variables are _actually_ used (these are the ones that are left in the AST), and later we removed the ones that weren't part of known used list. Moving the logic to this step feels a natural spot for this to happen, because we are in fact optimizing the AST. We were already walking the AST, so we can just handle these cases while we are walking without additional walks. Last but not least, this also means that there is only a single spot where need to track and remove variables. Now, there is a different part to this story. If you use a variable in JS land for example, we also want to make sure that we keep the CSS variable in the CSS. To do this, we can mark variables as being used in the internal `Theme`. The Oxide scanner will also emit used variables that it can find such as `var(--color-red-500)` and will emit `--color-red-500` as a "candidate". We can then proactively mark this one as used even though it may not be used anyway in the actual AST. --- ### Always including all variables Some users might make heavy use of JavaScript and string interpolation where they _need_ all the variables to be present. Similar to the `inline` and `reference` theme options, this also exposes a new `static` option. This ensures that all the CSS variables will always be generated regardless of whether it's used or not. One handy feature is that you have granular control over this: ```css /* These will always be generated */ @theme static { --color-primary: red; --color-secondary: blue; } /* Only generated when used */ @theme { --color-maybe: pink; } ``` ### Performance considerations: Now that we are tracking which variables are being used, it means that we will produce a smaller CSS file, but we are also doing more work (the mark-and-sweep part). That said, ran some benchmarks and the changes look like this: Running it on Catalyst: <img width="1086" alt="image" src="https://github.com/user-attachments/assets/ec2124f0-2e64-4a11-aa5e-5f7ae6605962" /> _(probably within margin of error)_ Running it on Tailwind UI: <img width="1113" alt="image" src="https://github.com/user-attachments/assets/6bea2328-d790-4f33-a0ae-72654c688edb" /> ### Test plan - Tests have been updated with the removed CSS variables - Added a dedicated integration test to show that Oxide can find variables and mark them as used (so they are included) - Ran the code on Catalyst, and verified that all the removed variables are in fact not used anywhere in the codebase. The diff on Catalyst looks like this: <details> ```diff diff --git a/templates/catalyst/out.css b/templates/catalyst/out.css index f2b364ea..240d1d90 100644 --- a/templates/catalyst/out.css +++ b/templates/catalyst/out.css @@ -29,218 +29,111 @@ @layer theme { :root, :host { --font-sans: Inter, sans-serif; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - --color-red-50: oklch(0.971 0.013 17.38); - --color-red-100: oklch(0.936 0.032 17.717); --color-red-200: oklch(0.885 0.062 18.334); --color-red-300: oklch(0.808 0.114 19.571); --color-red-400: oklch(0.704 0.191 22.216); --color-red-500: oklch(0.637 0.237 25.331); --color-red-600: oklch(0.577 0.245 27.325); --color-red-700: oklch(0.505 0.213 27.518); - --color-red-800: oklch(0.444 0.177 26.899); --color-red-900: oklch(0.396 0.141 25.723); - --color-red-950: oklch(0.258 0.092 26.042); - --color-orange-50: oklch(0.98 0.016 73.684); - --color-orange-100: oklch(0.954 0.038 75.164); --color-orange-200: oklch(0.901 0.076 70.697); --color-orange-300: oklch(0.837 0.128 66.29); --color-orange-400: oklch(0.75 0.183 55.934); --color-orange-500: oklch(0.705 0.213 47.604); --color-orange-600: oklch(0.646 0.222 41.116); --color-orange-700: oklch(0.553 0.195 38.402); - --color-orange-800: oklch(0.47 0.157 37.304); --color-orange-900: oklch(0.408 0.123 38.172); - --color-orange-950: oklch(0.266 0.079 36.259); - --color-amber-50: oklch(0.987 0.022 95.277); - --color-amber-100: oklch(0.962 0.059 95.617); - --color-amber-200: oklch(0.924 0.12 95.746); - --color-amber-300: oklch(0.879 0.169 91.605); --color-amber-400: oklch(0.828 0.189 84.429); --color-amber-500: oklch(0.769 0.188 70.08); --color-amber-600: oklch(0.666 0.179 58.318); --color-amber-700: oklch(0.555 0.163 48.998); - --color-amber-800: oklch(0.473 0.137 46.201); - --color-amber-900: oklch(0.414 0.112 45.904); --color-amber-950: oklch(0.279 0.077 45.635); - --color-yellow-50: oklch(0.987 0.026 102.212); - --color-yellow-100: oklch(0.973 0.071 103.193); - --color-yellow-200: oklch(0.945 0.129 101.54); --color-yellow-300: oklch(0.905 0.182 98.111); --color-yellow-400: oklch(0.852 0.199 91.936); - --color-yellow-500: oklch(0.795 0.184 86.047); --color-yellow-600: oklch(0.681 0.162 75.834); --color-yellow-700: oklch(0.554 0.135 66.442); - --color-yellow-800: oklch(0.476 0.114 61.907); - --color-yellow-900: oklch(0.421 0.095 57.708); --color-yellow-950: oklch(0.286 0.066 53.813); - --color-lime-50: oklch(0.986 0.031 120.757); - --color-lime-100: oklch(0.967 0.067 122.328); - --color-lime-200: oklch(0.938 0.127 124.321); --color-lime-300: oklch(0.897 0.196 126.665); --color-lime-400: oklch(0.841 0.238 128.85); - --color-lime-500: oklch(0.768 0.233 130.85); --color-lime-600: oklch(0.648 0.2 131.684); --color-lime-700: oklch(0.532 0.157 131.589); - --color-lime-800: oklch(0.453 0.124 130.933); - --color-lime-900: oklch(0.405 0.101 131.063); --color-lime-950: oklch(0.274 0.072 132.109); - --color-green-50: oklch(0.982 0.018 155.826); - --color-green-100: oklch(0.962 0.044 156.743); - --color-green-200: oklch(0.925 0.084 155.995); - --color-green-300: oklch(0.871 0.15 154.449); --color-green-400: oklch(0.792 0.209 151.711); --color-green-500: oklch(0.723 0.219 149.579); --color-green-600: oklch(0.627 0.194 149.214); --color-green-700: oklch(0.527 0.154 150.069); - --color-green-800: oklch(0.448 0.119 151.328); --color-green-900: oklch(0.393 0.095 152.535); - --color-green-950: oklch(0.266 0.065 152.934); - --color-emerald-50: oklch(0.979 0.021 166.113); - --color-emerald-100: oklch(0.95 0.052 163.051); - --color-emerald-200: oklch(0.905 0.093 164.15); - --color-emerald-300: oklch(0.845 0.143 164.978); --color-emerald-400: oklch(0.765 0.177 163.223); --color-emerald-500: oklch(0.696 0.17 162.48); --color-emerald-600: oklch(0.596 0.145 163.225); --color-emerald-700: oklch(0.508 0.118 165.612); - --color-emerald-800: oklch(0.432 0.095 166.913); --color-emerald-900: oklch(0.378 0.077 168.94); - --color-emerald-950: oklch(0.262 0.051 172.552); - --color-teal-50: oklch(0.984 0.014 180.72); - --color-teal-100: oklch(0.953 0.051 180.801); - --color-teal-200: oklch(0.91 0.096 180.426); --color-teal-300: oklch(0.855 0.138 181.071); --color-teal-400: oklch(0.777 0.152 181.912); --color-teal-500: oklch(0.704 0.14 182.503); --color-teal-600: oklch(0.6 0.118 184.704); --color-teal-700: oklch(0.511 0.096 186.391); - --color-teal-800: oklch(0.437 0.078 188.216); --color-teal-900: oklch(0.386 0.063 188.416); - --color-teal-950: oklch(0.277 0.046 192.524); - --color-cyan-50: oklch(0.984 0.019 200.873); - --color-cyan-100: oklch(0.956 0.045 203.388); - --color-cyan-200: oklch(0.917 0.08 205.041); --color-cyan-300: oklch(0.865 0.127 207.078); --color-cyan-400: oklch(0.789 0.154 211.53); --color-cyan-500: oklch(0.715 0.143 215.221); - --color-cyan-600: oklch(0.609 0.126 221.723); --color-cyan-700: oklch(0.52 0.105 223.128); - --color-cyan-800: oklch(0.45 0.085 224.283); - --color-cyan-900: oklch(0.398 0.07 227.392); --color-cyan-950: oklch(0.302 0.056 229.695); - --color-sky-50: oklch(0.977 0.013 236.62); - --color-sky-100: oklch(0.951 0.026 236.824); - --color-sky-200: oklch(0.901 0.058 230.902); --color-sky-300: oklch(0.828 0.111 230.318); - --color-sky-400: oklch(0.746 0.16 232.661); --color-sky-500: oklch(0.685 0.169 237.323); --color-sky-600: oklch(0.588 0.158 241.966); --color-sky-700: oklch(0.5 0.134 242.749); - --color-sky-800: oklch(0.443 0.11 240.79); --color-sky-900: oklch(0.391 0.09 240.876); - --color-sky-950: oklch(0.293 0.066 243.157); - --color-blue-50: oklch(0.97 0.014 254.604); - --color-blue-100: oklch(0.932 0.032 255.585); - --color-blue-200: oklch(0.882 0.059 254.128); --color-blue-300: oklch(0.809 0.105 251.813); --color-blue-400: oklch(0.707 0.165 254.624); --color-blue-500: oklch(0.623 0.214 259.815); --color-blue-600: oklch(0.546 0.245 262.881); --color-blue-700: oklch(0.488 0.243 264.376); - --color-blue-800: oklch(0.424 0.199 265.638); --color-blue-900: oklch(0.379 0.146 265.522); - --color-blue-950: oklch(0.282 0.091 267.935); - --color-indigo-50: oklch(0.962 0.018 272.314); - --color-indigo-100: oklch(0.93 0.034 272.788); --color-indigo-200: oklch(0.87 0.065 274.039); --color-indigo-300: oklch(0.785 0.115 274.713); --color-indigo-400: oklch(0.673 0.182 276.935); --color-indigo-500: oklch(0.585 0.233 277.117); --color-indigo-600: oklch(0.511 0.262 276.966); --color-indigo-700: oklch(0.457 0.24 277.023); - --color-indigo-800: oklch(0.398 0.195 277.366); --color-indigo-900: oklch(0.359 0.144 278.697); - --color-indigo-950: oklch(0.257 0.09 281.288); - --color-violet-50: oklch(0.969 0.016 293.756); - --color-violet-100: oklch(0.943 0.029 294.588); --color-violet-200: oklch(0.894 0.057 293.283); --color-violet-300: oklch(0.811 0.111 293.571); --color-violet-400: oklch(0.702 0.183 293.541); --color-violet-500: oklch(0.606 0.25 292.717); --color-violet-600: oklch(0.541 0.281 293.009); --color-violet-700: oklch(0.491 0.27 292.581); - --color-violet-800: oklch(0.432 0.232 292.759); --color-violet-900: oklch(0.38 0.189 293.745); - --color-violet-950: oklch(0.283 0.141 291.089); - --color-purple-50: oklch(0.977 0.014 308.299); - --color-purple-100: oklch(0.946 0.033 307.174); --color-purple-200: oklch(0.902 0.063 306.703); --color-purple-300: oklch(0.827 0.119 306.383); --color-purple-400: oklch(0.714 0.203 305.504); --color-purple-500: oklch(0.627 0.265 303.9); --color-purple-600: oklch(0.558 0.288 302.321); --color-purple-700: oklch(0.496 0.265 301.924); - --color-purple-800: oklch(0.438 0.218 303.724); --color-purple-900: oklch(0.381 0.176 304.987); - --color-purple-950: oklch(0.291 0.149 302.717); - --color-fuchsia-50: oklch(0.977 0.017 320.058); - --color-fuchsia-100: oklch(0.952 0.037 318.852); --color-fuchsia-200: oklch(0.903 0.076 319.62); --color-fuchsia-300: oklch(0.833 0.145 321.434); --color-fuchsia-400: oklch(0.74 0.238 322.16); --color-fuchsia-500: oklch(0.667 0.295 322.15); --color-fuchsia-600: oklch(0.591 0.293 322.896); --color-fuchsia-700: oklch(0.518 0.253 323.949); - --color-fuchsia-800: oklch(0.452 0.211 324.591); --color-fuchsia-900: oklch(0.401 0.17 325.612); - --color-fuchsia-950: oklch(0.293 0.136 325.661); - --color-pink-50: oklch(0.971 0.014 343.198); - --color-pink-100: oklch(0.948 0.028 342.258); --color-pink-200: oklch(0.899 0.061 343.231); --color-pink-300: oklch(0.823 0.12 346.018); --color-pink-400: oklch(0.718 0.202 349.761); --color-pink-500: oklch(0.656 0.241 354.308); --color-pink-600: oklch(0.592 0.249 0.584); --color-pink-700: oklch(0.525 0.223 3.958); - --color-pink-800: oklch(0.459 0.187 3.815); --color-pink-900: oklch(0.408 0.153 2.432); - --color-pink-950: oklch(0.284 0.109 3.907); - --color-rose-50: oklch(0.969 0.015 12.422); - --color-rose-100: oklch(0.941 0.03 12.58); --color-rose-200: oklch(0.892 0.058 10.001); --color-rose-300: oklch(0.81 0.117 11.638); --color-rose-400: oklch(0.712 0.194 13.428); --color-rose-500: oklch(0.645 0.246 16.439); --color-rose-600: oklch(0.586 0.253 17.585); --color-rose-700: oklch(0.514 0.222 16.935); - --color-rose-800: oklch(0.455 0.188 13.697); --color-rose-900: oklch(0.41 0.159 10.272); - --color-rose-950: oklch(0.271 0.105 12.094); - --color-slate-50: oklch(0.984 0.003 247.858); - --color-slate-100: oklch(0.968 0.007 247.896); - --color-slate-200: oklch(0.929 0.013 255.508); - --color-slate-300: oklch(0.869 0.022 252.894); - --color-slate-400: oklch(0.704 0.04 256.788); - --color-slate-500: oklch(0.554 0.046 257.417); - --color-slate-600: oklch(0.446 0.043 257.281); - --color-slate-700: oklch(0.372 0.044 257.287); - --color-slate-800: oklch(0.279 0.041 260.031); - --color-slate-900: oklch(0.208 0.042 265.755); - --color-slate-950: oklch(0.129 0.042 264.695); - --color-gray-50: oklch(0.985 0.002 247.839); - --color-gray-100: oklch(0.967 0.003 264.542); - --color-gray-200: oklch(0.928 0.006 264.531); - --color-gray-300: oklch(0.872 0.01 258.338); - --color-gray-400: oklch(0.707 0.022 261.325); - --color-gray-500: oklch(0.551 0.027 264.364); - --color-gray-600: oklch(0.446 0.03 256.802); - --color-gray-700: oklch(0.373 0.034 259.733); - --color-gray-800: oklch(0.278 0.033 256.848); - --color-gray-900: oklch(0.21 0.034 264.665); - --color-gray-950: oklch(0.13 0.028 261.692); --color-zinc-50: oklch(0.985 0 0); --color-zinc-100: oklch(0.967 0.001 286.375); --color-zinc-200: oklch(0.92 0.004 286.32); @@ -252,38 +145,9 @@ --color-zinc-800: oklch(0.274 0.006 286.033); --color-zinc-900: oklch(0.21 0.006 285.885); --color-zinc-950: oklch(0.141 0.005 285.823); - --color-neutral-50: oklch(0.985 0 0); - --color-neutral-100: oklch(0.97 0 0); - --color-neutral-200: oklch(0.922 0 0); - --color-neutral-300: oklch(0.87 0 0); - --color-neutral-400: oklch(0.708 0 0); - --color-neutral-500: oklch(0.556 0 0); - --color-neutral-600: oklch(0.439 0 0); - --color-neutral-700: oklch(0.371 0 0); - --color-neutral-800: oklch(0.269 0 0); - --color-neutral-900: oklch(0.205 0 0); - --color-neutral-950: oklch(0.145 0 0); - --color-stone-50: oklch(0.985 0.001 106.423); - --color-stone-100: oklch(0.97 0.001 106.424); - --color-stone-200: oklch(0.923 0.003 48.717); - --color-stone-300: oklch(0.869 0.005 56.366); - --color-stone-400: oklch(0.709 0.01 56.259); - --color-stone-500: oklch(0.553 0.013 58.071); - --color-stone-600: oklch(0.444 0.011 73.639); - --color-stone-700: oklch(0.374 0.01 67.558); - --color-stone-800: oklch(0.268 0.007 34.298); - --color-stone-900: oklch(0.216 0.006 56.043); - --color-stone-950: oklch(0.147 0.004 49.25); --color-black: #000; --color-white: #fff; --spacing: 0.25rem; - --breakpoint-sm: 40rem; - --breakpoint-md: 48rem; - --breakpoint-lg: 64rem; - --breakpoint-xl: 80rem; - --breakpoint-2xl: 96rem; - --container-3xs: 16rem; - --container-2xs: 18rem; --container-xs: 20rem; --container-sm: 24rem; --container-md: 28rem; @@ -302,92 +166,23 @@ --text-base: 1rem; --text-base--line-height: calc(1.5 / 1); --text-lg: 1.125rem; - --text-lg--line-height: calc(1.75 / 1.125); --text-xl: 1.25rem; - --text-xl--line-height: calc(1.75 / 1.25); --text-2xl: 1.5rem; - --text-2xl--line-height: calc(2 / 1.5); - --text-3xl: 1.875rem; - --text-3xl--line-height: calc(2.25 / 1.875); - --text-4xl: 2.25rem; - --text-4xl--line-height: calc(2.5 / 2.25); - --text-5xl: 3rem; - --text-5xl--line-height: 1; - --text-6xl: 3.75rem; - --text-6xl--line-height: 1; - --text-7xl: 4.5rem; - --text-7xl--line-height: 1; - --text-8xl: 6rem; - --text-8xl--line-height: 1; - --text-9xl: 8rem; - --text-9xl--line-height: 1; - --font-weight-thin: 100; - --font-weight-extralight: 200; - --font-weight-light: 300; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; - --font-weight-extrabold: 800; - --font-weight-black: 900; - --tracking-tighter: -0.05em; - --tracking-tight: -0.025em; - --tracking-normal: 0em; - --tracking-wide: 0.025em; - --tracking-wider: 0.05em; - --tracking-widest: 0.1em; - --leading-tight: 1.25; - --leading-snug: 1.375; - --leading-normal: 1.5; - --leading-relaxed: 1.625; - --leading-loose: 2; - --radius-xs: 0.125rem; --radius-sm: 0.25rem; --radius-md: 0.375rem; --radius-lg: 0.5rem; --radius-xl: 0.75rem; --radius-2xl: 1rem; --radius-3xl: 1.5rem; - --radius-4xl: 2rem; - --shadow-2xs: 0 1px rgb(0 0 0 / 0.05); - --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05); - --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); - --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), - 0 2px 4px -2px rgb(0 0 0 / 0.1); - --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), - 0 4px 6px -4px rgb(0 0 0 / 0.1); - --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), - 0 8px 10px -6px rgb(0 0 0 / 0.1); - --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25); - --inset-shadow-2xs: inset 0 1px rgb(0 0 0 / 0.05); - --inset-shadow-xs: inset 0 1px 1px rgb(0 0 0 / 0.05); - --inset-shadow-sm: inset 0 2px 4px rgb(0 0 0 / 0.05); - --drop-shadow-xs: 0 1px 1px rgb(0 0 0 / 0.05); - --drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15); - --drop-shadow-md: 0 3px 3px rgb(0 0 0 / 0.12); - --drop-shadow-lg: 0 4px 4px rgb(0 0 0 / 0.15); - --drop-shadow-xl: 0 9px 7px rgb(0 0 0 / 0.1); - --drop-shadow-2xl: 0 25px 25px rgb(0 0 0 / 0.15); --ease-in: cubic-bezier(0.4, 0, 1, 1); --ease-out: cubic-bezier(0, 0, 0.2, 1); --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); - --animate-spin: spin 1s linear infinite; - --animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; - --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; - --animate-bounce: bounce 1s infinite; - --blur-xs: 4px; - --blur-sm: 8px; --blur-md: 12px; - --blur-lg: 16px; --blur-xl: 24px; - --blur-2xl: 40px; - --blur-3xl: 64px; - --perspective-dramatic: 100px; - --perspective-near: 300px; - --perspective-normal: 500px; - --perspective-midrange: 800px; - --perspective-distant: 1200px; - --aspect-video: 16 / 9; --default-transition-duration: 150ms; --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); --default-font-family: var(--font-sans); ``` </details> If you have `ripgrep` installed, you can use this command to verify that these variables are indeed not used anywhere: <details> ```shell rg "\-\-font-serif\b" rg "\-\-color-red-50\b" rg "\-\-color-red-100\b" rg "\-\-color-red-800\b" rg "\-\-color-red-950\b" rg "\-\-color-orange-50\b" rg "\-\-color-orange-100\b" rg "\-\-color-orange-800\b" rg "\-\-color-orange-950\b" rg "\-\-color-amber-50\b" rg "\-\-color-amber-100\b" rg "\-\-color-amber-200\b" rg "\-\-color-amber-300\b" rg "\-\-color-amber-800\b" rg "\-\-color-amber-900\b" rg "\-\-color-yellow-50\b" rg "\-\-color-yellow-100\b" rg "\-\-color-yellow-200\b" rg "\-\-color-yellow-500\b" rg "\-\-color-yellow-800\b" rg "\-\-color-yellow-900\b" rg "\-\-color-lime-50\b" rg "\-\-color-lime-100\b" rg "\-\-color-lime-200\b" rg "\-\-color-lime-500\b" rg "\-\-color-lime-800\b" rg "\-\-color-lime-900\b" rg "\-\-color-green-50\b" rg "\-\-color-green-100\b" rg "\-\-color-green-200\b" rg "\-\-color-green-300\b" rg "\-\-color-green-800\b" rg "\-\-color-green-950\b" rg "\-\-color-emerald-50\b" rg "\-\-color-emerald-100\b" rg "\-\-color-emerald-200\b" rg "\-\-color-emerald-300\b" rg "\-\-color-emerald-800\b" rg "\-\-color-emerald-950\b" rg "\-\-color-teal-50\b" rg "\-\-color-teal-100\b" rg "\-\-color-teal-200\b" rg "\-\-color-teal-800\b" rg "\-\-color-teal-950\b" rg "\-\-color-cyan-50\b" rg "\-\-color-cyan-100\b" rg "\-\-color-cyan-200\b" rg "\-\-color-cyan-600\b" rg "\-\-color-cyan-800\b" rg "\-\-color-cyan-900\b" rg "\-\-color-sky-50\b" rg "\-\-color-sky-100\b" rg "\-\-color-sky-200\b" rg "\-\-color-sky-400\b" rg "\-\-color-sky-800\b" rg "\-\-color-sky-950\b" rg "\-\-color-blue-50\b" rg "\-\-color-blue-100\b" rg "\-\-color-blue-200\b" rg "\-\-color-blue-800\b" rg "\-\-color-blue-950\b" rg "\-\-color-indigo-50\b" rg "\-\-color-indigo-100\b" rg "\-\-color-indigo-800\b" rg "\-\-color-indigo-950\b" rg "\-\-color-violet-50\b" rg "\-\-color-violet-100\b" rg "\-\-color-violet-800\b" rg "\-\-color-violet-950\b" rg "\-\-color-purple-50\b" rg "\-\-color-purple-100\b" rg "\-\-color-purple-800\b" rg "\-\-color-purple-950\b" rg "\-\-color-fuchsia-50\b" rg "\-\-color-fuchsia-100\b" rg "\-\-color-fuchsia-800\b" rg "\-\-color-fuchsia-950\b" rg "\-\-color-pink-50\b" rg "\-\-color-pink-100\b" rg "\-\-color-pink-800\b" rg "\-\-color-pink-950\b" rg "\-\-color-rose-50\b" rg "\-\-color-rose-100\b" rg "\-\-color-rose-800\b" rg "\-\-color-rose-950\b" rg "\-\-color-slate-50\b" rg "\-\-color-slate-100\b" rg "\-\-color-slate-200\b" rg "\-\-color-slate-300\b" rg "\-\-color-slate-400\b" rg "\-\-color-slate-500\b" rg "\-\-color-slate-600\b" rg "\-\-color-slate-700\b" rg "\-\-color-slate-800\b" rg "\-\-color-slate-900\b" rg "\-\-color-slate-950\b" rg "\-\-color-gray-50\b" rg "\-\-color-gray-100\b" rg "\-\-color-gray-200\b" rg "\-\-color-gray-300\b" rg "\-\-color-gray-400\b" rg "\-\-color-gray-500\b" rg "\-\-color-gray-600\b" rg "\-\-color-gray-700\b" rg "\-\-color-gray-800\b" rg "\-\-color-gray-900\b" rg "\-\-color-gray-950\b" rg "\-\-color-neutral-50\b" rg "\-\-color-neutral-100\b" rg "\-\-color-neutral-200\b" rg "\-\-color-neutral-300\b" rg "\-\-color-neutral-400\b" rg "\-\-color-neutral-500\b" rg "\-\-color-neutral-600\b" rg "\-\-color-neutral-700\b" rg "\-\-color-neutral-800\b" rg "\-\-color-neutral-900\b" rg "\-\-color-neutral-950\b" rg "\-\-color-stone-50\b" rg "\-\-color-stone-100\b" rg "\-\-color-stone-200\b" rg "\-\-color-stone-300\b" rg "\-\-color-stone-400\b" rg "\-\-color-stone-500\b" rg "\-\-color-stone-600\b" rg "\-\-color-stone-700\b" rg "\-\-color-stone-800\b" rg "\-\-color-stone-900\b" rg "\-\-color-stone-950\b" rg "\-\-breakpoint-sm\b" rg "\-\-breakpoint-md\b" rg "\-\-breakpoint-lg\b" rg "\-\-breakpoint-xl\b" rg "\-\-breakpoint-2xl\b" rg "\-\-container-3xs\b" rg "\-\-container-2xs\b" rg "\-\-text-lg--line-height\b" rg "\-\-text-xl--line-height\b" rg "\-\-text-2xl--line-height\b" rg "\-\-text-3xl\b" rg "\-\-text-3xl--line-height\b" rg "\-\-text-4xl\b" rg "\-\-text-4xl--line-height\b" rg "\-\-text-5xl\b" rg "\-\-text-5xl--line-height\b" rg "\-\-text-6xl\b" rg "\-\-text-6xl--line-height\b" rg "\-\-text-7xl\b" rg "\-\-text-7xl--line-height\b" rg "\-\-text-8xl\b" rg "\-\-text-8xl--line-height\b" rg "\-\-text-9xl\b" rg "\-\-text-9xl--line-height\b" rg "\-\-font-weight-thin\b" rg "\-\-font-weight-extralight\b" rg "\-\-font-weight-light\b" rg "\-\-font-weight-extrabold\b" rg "\-\-font-weight-black\b" rg "\-\-tracking-tighter\b" rg "\-\-tracking-tight\b" rg "\-\-tracking-normal\b" rg "\-\-tracking-wide\b" rg "\-\-tracking-wider\b" rg "\-\-tracking-widest\b" rg "\-\-leading-tight\b" rg "\-\-leading-snug\b" rg "\-\-leading-normal\b" rg "\-\-leading-relaxed\b" rg "\-\-leading-loose\b" rg "\-\-radius-xs\b" rg "\-\-radius-4xl\b" rg "\-\-shadow-2xs\b" rg "\-\-shadow-xs\b" rg "\-\-shadow-sm\b" rg "\-\-shadow-md\b" rg "\-\-shadow-lg\b" rg "\-\-shadow-xl\b" rg "\-\-shadow-2xl\b" rg "\-\-inset-shadow-2xs\b" rg "\-\-inset-shadow-xs\b" rg "\-\-inset-shadow-sm\b" rg "\-\-drop-shadow-xs\b" rg "\-\-drop-shadow-sm\b" rg "\-\-drop-shadow-md\b" rg "\-\-drop-shadow-lg\b" rg "\-\-drop-shadow-xl\b" rg "\-\-drop-shadow-2xl\b" rg "\-\-animate-spin\b" rg "\-\-animate-ping\b" rg "\-\-animate-pulse\b" rg "\-\-animate-bounce\b" rg "\-\-blur-xs\b" rg "\-\-blur-sm\b" rg "\-\-blur-lg\b" rg "\-\-blur-2xl\b" rg "\-\-blur-3xl\b" rg "\-\-perspective-dramatic\b" rg "\-\-perspective-near\b" rg "\-\-perspective-normal\b" rg "\-\-perspective-midrange\b" rg "\-\-perspective-distant\b" rg "\-\-aspect-video\b" ``` </details> The only exception I noticed is that we have this: ```css src/typography.utilities.css 10: @media (width >= theme(--breakpoint-sm)) { ``` But this is not a variable, but it's replaced at build time with the actual value, so this is not a real issue. Testing on other templates: <img width="2968" alt="image" src="https://github.com/user-attachments/assets/cabf121d-4cb9-468f-9cf5-ceb02609dc7d" /> Fixes: https://github.com/tailwindlabs/tailwindcss/issues/16145 --------- Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2025-02-07 18:12:47 +01:00
".custom-css {
color: red;
}"
`)
expect(before).toMatchInlineSnapshot(`
"@theme {
--color-red-500: red;
}
.custom-css {
color: theme(--color-red-500);
}"
`)
expect(after).toMatchInlineSnapshot(`
Only expose used CSS variables (#16211) This PR only exposes used CSS variables. My initial approach was to track the used variables, this was a bit messy because it meant that we had to walk part of the AST(s) in multiple places. We also had to be careful because sometimes if a variable exists in an AST, that doesn't mean that it's actually used. E.g.: ```css h1 { color: var(--color-red-500); /* Definitely used, so let's keep it */ } @utility foo { color: var(--color-blue-500); /* Hmm, used? */ } ``` In this last case, the `--color-blue-500` is part of the CSS AST, but as long as `foo` the utility is not used, it won't end up in your actual CSS file, therefore the variable is **not** used. Alternatively, if the `foo` utility is used with an invalid variant (e.g.: `group-[>.foo]:foo`, then the `@utility foo` code will still run internally because variants are applied on top of the utility. This means that it looks like `var(--color-blue-500)` is being used. Another annoying side effect was that because variables are conditionally generated, that the `@theme` -> `:root, :host` conversion had to happen for every build, instead of once in the `compile(…)` step. --- To prevent all the messy rules and additional booking while walking of ASTs I thought about a different approach. We are only interested in variables that are actually used. The only way we know for sure, is right before the `toCss(…)` step. Any step before that could still throw away AST nodes. However, we do have an `optimizeAst` step right before printing to simplify and optimize the AST. So the idea was to keep all the CSS variables in the AST, and only in the `optimizeAst` step we perform a kind of mark-and-sweep algorithm where we can first check which variables are _actually_ used (these are the ones that are left in the AST), and later we removed the ones that weren't part of known used list. Moving the logic to this step feels a natural spot for this to happen, because we are in fact optimizing the AST. We were already walking the AST, so we can just handle these cases while we are walking without additional walks. Last but not least, this also means that there is only a single spot where need to track and remove variables. Now, there is a different part to this story. If you use a variable in JS land for example, we also want to make sure that we keep the CSS variable in the CSS. To do this, we can mark variables as being used in the internal `Theme`. The Oxide scanner will also emit used variables that it can find such as `var(--color-red-500)` and will emit `--color-red-500` as a "candidate". We can then proactively mark this one as used even though it may not be used anyway in the actual AST. --- ### Always including all variables Some users might make heavy use of JavaScript and string interpolation where they _need_ all the variables to be present. Similar to the `inline` and `reference` theme options, this also exposes a new `static` option. This ensures that all the CSS variables will always be generated regardless of whether it's used or not. One handy feature is that you have granular control over this: ```css /* These will always be generated */ @theme static { --color-primary: red; --color-secondary: blue; } /* Only generated when used */ @theme { --color-maybe: pink; } ``` ### Performance considerations: Now that we are tracking which variables are being used, it means that we will produce a smaller CSS file, but we are also doing more work (the mark-and-sweep part). That said, ran some benchmarks and the changes look like this: Running it on Catalyst: <img width="1086" alt="image" src="https://github.com/user-attachments/assets/ec2124f0-2e64-4a11-aa5e-5f7ae6605962" /> _(probably within margin of error)_ Running it on Tailwind UI: <img width="1113" alt="image" src="https://github.com/user-attachments/assets/6bea2328-d790-4f33-a0ae-72654c688edb" /> ### Test plan - Tests have been updated with the removed CSS variables - Added a dedicated integration test to show that Oxide can find variables and mark them as used (so they are included) - Ran the code on Catalyst, and verified that all the removed variables are in fact not used anywhere in the codebase. The diff on Catalyst looks like this: <details> ```diff diff --git a/templates/catalyst/out.css b/templates/catalyst/out.css index f2b364ea..240d1d90 100644 --- a/templates/catalyst/out.css +++ b/templates/catalyst/out.css @@ -29,218 +29,111 @@ @layer theme { :root, :host { --font-sans: Inter, sans-serif; - --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - --color-red-50: oklch(0.971 0.013 17.38); - --color-red-100: oklch(0.936 0.032 17.717); --color-red-200: oklch(0.885 0.062 18.334); --color-red-300: oklch(0.808 0.114 19.571); --color-red-400: oklch(0.704 0.191 22.216); --color-red-500: oklch(0.637 0.237 25.331); --color-red-600: oklch(0.577 0.245 27.325); --color-red-700: oklch(0.505 0.213 27.518); - --color-red-800: oklch(0.444 0.177 26.899); --color-red-900: oklch(0.396 0.141 25.723); - --color-red-950: oklch(0.258 0.092 26.042); - --color-orange-50: oklch(0.98 0.016 73.684); - --color-orange-100: oklch(0.954 0.038 75.164); --color-orange-200: oklch(0.901 0.076 70.697); --color-orange-300: oklch(0.837 0.128 66.29); --color-orange-400: oklch(0.75 0.183 55.934); --color-orange-500: oklch(0.705 0.213 47.604); --color-orange-600: oklch(0.646 0.222 41.116); --color-orange-700: oklch(0.553 0.195 38.402); - --color-orange-800: oklch(0.47 0.157 37.304); --color-orange-900: oklch(0.408 0.123 38.172); - --color-orange-950: oklch(0.266 0.079 36.259); - --color-amber-50: oklch(0.987 0.022 95.277); - --color-amber-100: oklch(0.962 0.059 95.617); - --color-amber-200: oklch(0.924 0.12 95.746); - --color-amber-300: oklch(0.879 0.169 91.605); --color-amber-400: oklch(0.828 0.189 84.429); --color-amber-500: oklch(0.769 0.188 70.08); --color-amber-600: oklch(0.666 0.179 58.318); --color-amber-700: oklch(0.555 0.163 48.998); - --color-amber-800: oklch(0.473 0.137 46.201); - --color-amber-900: oklch(0.414 0.112 45.904); --color-amber-950: oklch(0.279 0.077 45.635); - --color-yellow-50: oklch(0.987 0.026 102.212); - --color-yellow-100: oklch(0.973 0.071 103.193); - --color-yellow-200: oklch(0.945 0.129 101.54); --color-yellow-300: oklch(0.905 0.182 98.111); --color-yellow-400: oklch(0.852 0.199 91.936); - --color-yellow-500: oklch(0.795 0.184 86.047); --color-yellow-600: oklch(0.681 0.162 75.834); --color-yellow-700: oklch(0.554 0.135 66.442); - --color-yellow-800: oklch(0.476 0.114 61.907); - --color-yellow-900: oklch(0.421 0.095 57.708); --color-yellow-950: oklch(0.286 0.066 53.813); - --color-lime-50: oklch(0.986 0.031 120.757); - --color-lime-100: oklch(0.967 0.067 122.328); - --color-lime-200: oklch(0.938 0.127 124.321); --color-lime-300: oklch(0.897 0.196 126.665); --color-lime-400: oklch(0.841 0.238 128.85); - --color-lime-500: oklch(0.768 0.233 130.85); --color-lime-600: oklch(0.648 0.2 131.684); --color-lime-700: oklch(0.532 0.157 131.589); - --color-lime-800: oklch(0.453 0.124 130.933); - --color-lime-900: oklch(0.405 0.101 131.063); --color-lime-950: oklch(0.274 0.072 132.109); - --color-green-50: oklch(0.982 0.018 155.826); - --color-green-100: oklch(0.962 0.044 156.743); - --color-green-200: oklch(0.925 0.084 155.995); - --color-green-300: oklch(0.871 0.15 154.449); --color-green-400: oklch(0.792 0.209 151.711); --color-green-500: oklch(0.723 0.219 149.579); --color-green-600: oklch(0.627 0.194 149.214); --color-green-700: oklch(0.527 0.154 150.069); - --color-green-800: oklch(0.448 0.119 151.328); --color-green-900: oklch(0.393 0.095 152.535); - --color-green-950: oklch(0.266 0.065 152.934); - --color-emerald-50: oklch(0.979 0.021 166.113); - --color-emerald-100: oklch(0.95 0.052 163.051); - --color-emerald-200: oklch(0.905 0.093 164.15); - --color-emerald-300: oklch(0.845 0.143 164.978); --color-emerald-400: oklch(0.765 0.177 163.223); --color-emerald-500: oklch(0.696 0.17 162.48); --color-emerald-600: oklch(0.596 0.145 163.225); --color-emerald-700: oklch(0.508 0.118 165.612); - --color-emerald-800: oklch(0.432 0.095 166.913); --color-emerald-900: oklch(0.378 0.077 168.94); - --color-emerald-950: oklch(0.262 0.051 172.552); - --color-teal-50: oklch(0.984 0.014 180.72); - --color-teal-100: oklch(0.953 0.051 180.801); - --color-teal-200: oklch(0.91 0.096 180.426); --color-teal-300: oklch(0.855 0.138 181.071); --color-teal-400: oklch(0.777 0.152 181.912); --color-teal-500: oklch(0.704 0.14 182.503); --color-teal-600: oklch(0.6 0.118 184.704); --color-teal-700: oklch(0.511 0.096 186.391); - --color-teal-800: oklch(0.437 0.078 188.216); --color-teal-900: oklch(0.386 0.063 188.416); - --color-teal-950: oklch(0.277 0.046 192.524); - --color-cyan-50: oklch(0.984 0.019 200.873); - --color-cyan-100: oklch(0.956 0.045 203.388); - --color-cyan-200: oklch(0.917 0.08 205.041); --color-cyan-300: oklch(0.865 0.127 207.078); --color-cyan-400: oklch(0.789 0.154 211.53); --color-cyan-500: oklch(0.715 0.143 215.221); - --color-cyan-600: oklch(0.609 0.126 221.723); --color-cyan-700: oklch(0.52 0.105 223.128); - --color-cyan-800: oklch(0.45 0.085 224.283); - --color-cyan-900: oklch(0.398 0.07 227.392); --color-cyan-950: oklch(0.302 0.056 229.695); - --color-sky-50: oklch(0.977 0.013 236.62); - --color-sky-100: oklch(0.951 0.026 236.824); - --color-sky-200: oklch(0.901 0.058 230.902); --color-sky-300: oklch(0.828 0.111 230.318); - --color-sky-400: oklch(0.746 0.16 232.661); --color-sky-500: oklch(0.685 0.169 237.323); --color-sky-600: oklch(0.588 0.158 241.966); --color-sky-700: oklch(0.5 0.134 242.749); - --color-sky-800: oklch(0.443 0.11 240.79); --color-sky-900: oklch(0.391 0.09 240.876); - --color-sky-950: oklch(0.293 0.066 243.157); - --color-blue-50: oklch(0.97 0.014 254.604); - --color-blue-100: oklch(0.932 0.032 255.585); - --color-blue-200: oklch(0.882 0.059 254.128); --color-blue-300: oklch(0.809 0.105 251.813); --color-blue-400: oklch(0.707 0.165 254.624); --color-blue-500: oklch(0.623 0.214 259.815); --color-blue-600: oklch(0.546 0.245 262.881); --color-blue-700: oklch(0.488 0.243 264.376); - --color-blue-800: oklch(0.424 0.199 265.638); --color-blue-900: oklch(0.379 0.146 265.522); - --color-blue-950: oklch(0.282 0.091 267.935); - --color-indigo-50: oklch(0.962 0.018 272.314); - --color-indigo-100: oklch(0.93 0.034 272.788); --color-indigo-200: oklch(0.87 0.065 274.039); --color-indigo-300: oklch(0.785 0.115 274.713); --color-indigo-400: oklch(0.673 0.182 276.935); --color-indigo-500: oklch(0.585 0.233 277.117); --color-indigo-600: oklch(0.511 0.262 276.966); --color-indigo-700: oklch(0.457 0.24 277.023); - --color-indigo-800: oklch(0.398 0.195 277.366); --color-indigo-900: oklch(0.359 0.144 278.697); - --color-indigo-950: oklch(0.257 0.09 281.288); - --color-violet-50: oklch(0.969 0.016 293.756); - --color-violet-100: oklch(0.943 0.029 294.588); --color-violet-200: oklch(0.894 0.057 293.283); --color-violet-300: oklch(0.811 0.111 293.571); --color-violet-400: oklch(0.702 0.183 293.541); --color-violet-500: oklch(0.606 0.25 292.717); --color-violet-600: oklch(0.541 0.281 293.009); --color-violet-700: oklch(0.491 0.27 292.581); - --color-violet-800: oklch(0.432 0.232 292.759); --color-violet-900: oklch(0.38 0.189 293.745); - --color-violet-950: oklch(0.283 0.141 291.089); - --color-purple-50: oklch(0.977 0.014 308.299); - --color-purple-100: oklch(0.946 0.033 307.174); --color-purple-200: oklch(0.902 0.063 306.703); --color-purple-300: oklch(0.827 0.119 306.383); --color-purple-400: oklch(0.714 0.203 305.504); --color-purple-500: oklch(0.627 0.265 303.9); --color-purple-600: oklch(0.558 0.288 302.321); --color-purple-700: oklch(0.496 0.265 301.924); - --color-purple-800: oklch(0.438 0.218 303.724); --color-purple-900: oklch(0.381 0.176 304.987); - --color-purple-950: oklch(0.291 0.149 302.717); - --color-fuchsia-50: oklch(0.977 0.017 320.058); - --color-fuchsia-100: oklch(0.952 0.037 318.852); --color-fuchsia-200: oklch(0.903 0.076 319.62); --color-fuchsia-300: oklch(0.833 0.145 321.434); --color-fuchsia-400: oklch(0.74 0.238 322.16); --color-fuchsia-500: oklch(0.667 0.295 322.15); --color-fuchsia-600: oklch(0.591 0.293 322.896); --color-fuchsia-700: oklch(0.518 0.253 323.949); - --color-fuchsia-800: oklch(0.452 0.211 324.591); --color-fuchsia-900: oklch(0.401 0.17 325.612); - --color-fuchsia-950: oklch(0.293 0.136 325.661); - --color-pink-50: oklch(0.971 0.014 343.198); - --color-pink-100: oklch(0.948 0.028 342.258); --color-pink-200: oklch(0.899 0.061 343.231); --color-pink-300: oklch(0.823 0.12 346.018); --color-pink-400: oklch(0.718 0.202 349.761); --color-pink-500: oklch(0.656 0.241 354.308); --color-pink-600: oklch(0.592 0.249 0.584); --color-pink-700: oklch(0.525 0.223 3.958); - --color-pink-800: oklch(0.459 0.187 3.815); --color-pink-900: oklch(0.408 0.153 2.432); - --color-pink-950: oklch(0.284 0.109 3.907); - --color-rose-50: oklch(0.969 0.015 12.422); - --color-rose-100: oklch(0.941 0.03 12.58); --color-rose-200: oklch(0.892 0.058 10.001); --color-rose-300: oklch(0.81 0.117 11.638); --color-rose-400: oklch(0.712 0.194 13.428); --color-rose-500: oklch(0.645 0.246 16.439); --color-rose-600: oklch(0.586 0.253 17.585); --color-rose-700: oklch(0.514 0.222 16.935); - --color-rose-800: oklch(0.455 0.188 13.697); --color-rose-900: oklch(0.41 0.159 10.272); - --color-rose-950: oklch(0.271 0.105 12.094); - --color-slate-50: oklch(0.984 0.003 247.858); - --color-slate-100: oklch(0.968 0.007 247.896); - --color-slate-200: oklch(0.929 0.013 255.508); - --color-slate-300: oklch(0.869 0.022 252.894); - --color-slate-400: oklch(0.704 0.04 256.788); - --color-slate-500: oklch(0.554 0.046 257.417); - --color-slate-600: oklch(0.446 0.043 257.281); - --color-slate-700: oklch(0.372 0.044 257.287); - --color-slate-800: oklch(0.279 0.041 260.031); - --color-slate-900: oklch(0.208 0.042 265.755); - --color-slate-950: oklch(0.129 0.042 264.695); - --color-gray-50: oklch(0.985 0.002 247.839); - --color-gray-100: oklch(0.967 0.003 264.542); - --color-gray-200: oklch(0.928 0.006 264.531); - --color-gray-300: oklch(0.872 0.01 258.338); - --color-gray-400: oklch(0.707 0.022 261.325); - --color-gray-500: oklch(0.551 0.027 264.364); - --color-gray-600: oklch(0.446 0.03 256.802); - --color-gray-700: oklch(0.373 0.034 259.733); - --color-gray-800: oklch(0.278 0.033 256.848); - --color-gray-900: oklch(0.21 0.034 264.665); - --color-gray-950: oklch(0.13 0.028 261.692); --color-zinc-50: oklch(0.985 0 0); --color-zinc-100: oklch(0.967 0.001 286.375); --color-zinc-200: oklch(0.92 0.004 286.32); @@ -252,38 +145,9 @@ --color-zinc-800: oklch(0.274 0.006 286.033); --color-zinc-900: oklch(0.21 0.006 285.885); --color-zinc-950: oklch(0.141 0.005 285.823); - --color-neutral-50: oklch(0.985 0 0); - --color-neutral-100: oklch(0.97 0 0); - --color-neutral-200: oklch(0.922 0 0); - --color-neutral-300: oklch(0.87 0 0); - --color-neutral-400: oklch(0.708 0 0); - --color-neutral-500: oklch(0.556 0 0); - --color-neutral-600: oklch(0.439 0 0); - --color-neutral-700: oklch(0.371 0 0); - --color-neutral-800: oklch(0.269 0 0); - --color-neutral-900: oklch(0.205 0 0); - --color-neutral-950: oklch(0.145 0 0); - --color-stone-50: oklch(0.985 0.001 106.423); - --color-stone-100: oklch(0.97 0.001 106.424); - --color-stone-200: oklch(0.923 0.003 48.717); - --color-stone-300: oklch(0.869 0.005 56.366); - --color-stone-400: oklch(0.709 0.01 56.259); - --color-stone-500: oklch(0.553 0.013 58.071); - --color-stone-600: oklch(0.444 0.011 73.639); - --color-stone-700: oklch(0.374 0.01 67.558); - --color-stone-800: oklch(0.268 0.007 34.298); - --color-stone-900: oklch(0.216 0.006 56.043); - --color-stone-950: oklch(0.147 0.004 49.25); --color-black: #000; --color-white: #fff; --spacing: 0.25rem; - --breakpoint-sm: 40rem; - --breakpoint-md: 48rem; - --breakpoint-lg: 64rem; - --breakpoint-xl: 80rem; - --breakpoint-2xl: 96rem; - --container-3xs: 16rem; - --container-2xs: 18rem; --container-xs: 20rem; --container-sm: 24rem; --container-md: 28rem; @@ -302,92 +166,23 @@ --text-base: 1rem; --text-base--line-height: calc(1.5 / 1); --text-lg: 1.125rem; - --text-lg--line-height: calc(1.75 / 1.125); --text-xl: 1.25rem; - --text-xl--line-height: calc(1.75 / 1.25); --text-2xl: 1.5rem; - --text-2xl--line-height: calc(2 / 1.5); - --text-3xl: 1.875rem; - --text-3xl--line-height: calc(2.25 / 1.875); - --text-4xl: 2.25rem; - --text-4xl--line-height: calc(2.5 / 2.25); - --text-5xl: 3rem; - --text-5xl--line-height: 1; - --text-6xl: 3.75rem; - --text-6xl--line-height: 1; - --text-7xl: 4.5rem; - --text-7xl--line-height: 1; - --text-8xl: 6rem; - --text-8xl--line-height: 1; - --text-9xl: 8rem; - --text-9xl--line-height: 1; - --font-weight-thin: 100; - --font-weight-extralight: 200; - --font-weight-light: 300; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; - --font-weight-extrabold: 800; - --font-weight-black: 900; - --tracking-tighter: -0.05em; - --tracking-tight: -0.025em; - --tracking-normal: 0em; - --tracking-wide: 0.025em; - --tracking-wider: 0.05em; - --tracking-widest: 0.1em; - --leading-tight: 1.25; - --leading-snug: 1.375; - --leading-normal: 1.5; - --leading-relaxed: 1.625; - --leading-loose: 2; - --radius-xs: 0.125rem; --radius-sm: 0.25rem; --radius-md: 0.375rem; --radius-lg: 0.5rem; --radius-xl: 0.75rem; --radius-2xl: 1rem; --radius-3xl: 1.5rem; - --radius-4xl: 2rem; - --shadow-2xs: 0 1px rgb(0 0 0 / 0.05); - --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05); - --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); - --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), - 0 2px 4px -2px rgb(0 0 0 / 0.1); - --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), - 0 4px 6px -4px rgb(0 0 0 / 0.1); - --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), - 0 8px 10px -6px rgb(0 0 0 / 0.1); - --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25); - --inset-shadow-2xs: inset 0 1px rgb(0 0 0 / 0.05); - --inset-shadow-xs: inset 0 1px 1px rgb(0 0 0 / 0.05); - --inset-shadow-sm: inset 0 2px 4px rgb(0 0 0 / 0.05); - --drop-shadow-xs: 0 1px 1px rgb(0 0 0 / 0.05); - --drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15); - --drop-shadow-md: 0 3px 3px rgb(0 0 0 / 0.12); - --drop-shadow-lg: 0 4px 4px rgb(0 0 0 / 0.15); - --drop-shadow-xl: 0 9px 7px rgb(0 0 0 / 0.1); - --drop-shadow-2xl: 0 25px 25px rgb(0 0 0 / 0.15); --ease-in: cubic-bezier(0.4, 0, 1, 1); --ease-out: cubic-bezier(0, 0, 0.2, 1); --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); - --animate-spin: spin 1s linear infinite; - --animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; - --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; - --animate-bounce: bounce 1s infinite; - --blur-xs: 4px; - --blur-sm: 8px; --blur-md: 12px; - --blur-lg: 16px; --blur-xl: 24px; - --blur-2xl: 40px; - --blur-3xl: 64px; - --perspective-dramatic: 100px; - --perspective-near: 300px; - --perspective-normal: 500px; - --perspective-midrange: 800px; - --perspective-distant: 1200px; - --aspect-video: 16 / 9; --default-transition-duration: 150ms; --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); --default-font-family: var(--font-sans); ``` </details> If you have `ripgrep` installed, you can use this command to verify that these variables are indeed not used anywhere: <details> ```shell rg "\-\-font-serif\b" rg "\-\-color-red-50\b" rg "\-\-color-red-100\b" rg "\-\-color-red-800\b" rg "\-\-color-red-950\b" rg "\-\-color-orange-50\b" rg "\-\-color-orange-100\b" rg "\-\-color-orange-800\b" rg "\-\-color-orange-950\b" rg "\-\-color-amber-50\b" rg "\-\-color-amber-100\b" rg "\-\-color-amber-200\b" rg "\-\-color-amber-300\b" rg "\-\-color-amber-800\b" rg "\-\-color-amber-900\b" rg "\-\-color-yellow-50\b" rg "\-\-color-yellow-100\b" rg "\-\-color-yellow-200\b" rg "\-\-color-yellow-500\b" rg "\-\-color-yellow-800\b" rg "\-\-color-yellow-900\b" rg "\-\-color-lime-50\b" rg "\-\-color-lime-100\b" rg "\-\-color-lime-200\b" rg "\-\-color-lime-500\b" rg "\-\-color-lime-800\b" rg "\-\-color-lime-900\b" rg "\-\-color-green-50\b" rg "\-\-color-green-100\b" rg "\-\-color-green-200\b" rg "\-\-color-green-300\b" rg "\-\-color-green-800\b" rg "\-\-color-green-950\b" rg "\-\-color-emerald-50\b" rg "\-\-color-emerald-100\b" rg "\-\-color-emerald-200\b" rg "\-\-color-emerald-300\b" rg "\-\-color-emerald-800\b" rg "\-\-color-emerald-950\b" rg "\-\-color-teal-50\b" rg "\-\-color-teal-100\b" rg "\-\-color-teal-200\b" rg "\-\-color-teal-800\b" rg "\-\-color-teal-950\b" rg "\-\-color-cyan-50\b" rg "\-\-color-cyan-100\b" rg "\-\-color-cyan-200\b" rg "\-\-color-cyan-600\b" rg "\-\-color-cyan-800\b" rg "\-\-color-cyan-900\b" rg "\-\-color-sky-50\b" rg "\-\-color-sky-100\b" rg "\-\-color-sky-200\b" rg "\-\-color-sky-400\b" rg "\-\-color-sky-800\b" rg "\-\-color-sky-950\b" rg "\-\-color-blue-50\b" rg "\-\-color-blue-100\b" rg "\-\-color-blue-200\b" rg "\-\-color-blue-800\b" rg "\-\-color-blue-950\b" rg "\-\-color-indigo-50\b" rg "\-\-color-indigo-100\b" rg "\-\-color-indigo-800\b" rg "\-\-color-indigo-950\b" rg "\-\-color-violet-50\b" rg "\-\-color-violet-100\b" rg "\-\-color-violet-800\b" rg "\-\-color-violet-950\b" rg "\-\-color-purple-50\b" rg "\-\-color-purple-100\b" rg "\-\-color-purple-800\b" rg "\-\-color-purple-950\b" rg "\-\-color-fuchsia-50\b" rg "\-\-color-fuchsia-100\b" rg "\-\-color-fuchsia-800\b" rg "\-\-color-fuchsia-950\b" rg "\-\-color-pink-50\b" rg "\-\-color-pink-100\b" rg "\-\-color-pink-800\b" rg "\-\-color-pink-950\b" rg "\-\-color-rose-50\b" rg "\-\-color-rose-100\b" rg "\-\-color-rose-800\b" rg "\-\-color-rose-950\b" rg "\-\-color-slate-50\b" rg "\-\-color-slate-100\b" rg "\-\-color-slate-200\b" rg "\-\-color-slate-300\b" rg "\-\-color-slate-400\b" rg "\-\-color-slate-500\b" rg "\-\-color-slate-600\b" rg "\-\-color-slate-700\b" rg "\-\-color-slate-800\b" rg "\-\-color-slate-900\b" rg "\-\-color-slate-950\b" rg "\-\-color-gray-50\b" rg "\-\-color-gray-100\b" rg "\-\-color-gray-200\b" rg "\-\-color-gray-300\b" rg "\-\-color-gray-400\b" rg "\-\-color-gray-500\b" rg "\-\-color-gray-600\b" rg "\-\-color-gray-700\b" rg "\-\-color-gray-800\b" rg "\-\-color-gray-900\b" rg "\-\-color-gray-950\b" rg "\-\-color-neutral-50\b" rg "\-\-color-neutral-100\b" rg "\-\-color-neutral-200\b" rg "\-\-color-neutral-300\b" rg "\-\-color-neutral-400\b" rg "\-\-color-neutral-500\b" rg "\-\-color-neutral-600\b" rg "\-\-color-neutral-700\b" rg "\-\-color-neutral-800\b" rg "\-\-color-neutral-900\b" rg "\-\-color-neutral-950\b" rg "\-\-color-stone-50\b" rg "\-\-color-stone-100\b" rg "\-\-color-stone-200\b" rg "\-\-color-stone-300\b" rg "\-\-color-stone-400\b" rg "\-\-color-stone-500\b" rg "\-\-color-stone-600\b" rg "\-\-color-stone-700\b" rg "\-\-color-stone-800\b" rg "\-\-color-stone-900\b" rg "\-\-color-stone-950\b" rg "\-\-breakpoint-sm\b" rg "\-\-breakpoint-md\b" rg "\-\-breakpoint-lg\b" rg "\-\-breakpoint-xl\b" rg "\-\-breakpoint-2xl\b" rg "\-\-container-3xs\b" rg "\-\-container-2xs\b" rg "\-\-text-lg--line-height\b" rg "\-\-text-xl--line-height\b" rg "\-\-text-2xl--line-height\b" rg "\-\-text-3xl\b" rg "\-\-text-3xl--line-height\b" rg "\-\-text-4xl\b" rg "\-\-text-4xl--line-height\b" rg "\-\-text-5xl\b" rg "\-\-text-5xl--line-height\b" rg "\-\-text-6xl\b" rg "\-\-text-6xl--line-height\b" rg "\-\-text-7xl\b" rg "\-\-text-7xl--line-height\b" rg "\-\-text-8xl\b" rg "\-\-text-8xl--line-height\b" rg "\-\-text-9xl\b" rg "\-\-text-9xl--line-height\b" rg "\-\-font-weight-thin\b" rg "\-\-font-weight-extralight\b" rg "\-\-font-weight-light\b" rg "\-\-font-weight-extrabold\b" rg "\-\-font-weight-black\b" rg "\-\-tracking-tighter\b" rg "\-\-tracking-tight\b" rg "\-\-tracking-normal\b" rg "\-\-tracking-wide\b" rg "\-\-tracking-wider\b" rg "\-\-tracking-widest\b" rg "\-\-leading-tight\b" rg "\-\-leading-snug\b" rg "\-\-leading-normal\b" rg "\-\-leading-relaxed\b" rg "\-\-leading-loose\b" rg "\-\-radius-xs\b" rg "\-\-radius-4xl\b" rg "\-\-shadow-2xs\b" rg "\-\-shadow-xs\b" rg "\-\-shadow-sm\b" rg "\-\-shadow-md\b" rg "\-\-shadow-lg\b" rg "\-\-shadow-xl\b" rg "\-\-shadow-2xl\b" rg "\-\-inset-shadow-2xs\b" rg "\-\-inset-shadow-xs\b" rg "\-\-inset-shadow-sm\b" rg "\-\-drop-shadow-xs\b" rg "\-\-drop-shadow-sm\b" rg "\-\-drop-shadow-md\b" rg "\-\-drop-shadow-lg\b" rg "\-\-drop-shadow-xl\b" rg "\-\-drop-shadow-2xl\b" rg "\-\-animate-spin\b" rg "\-\-animate-ping\b" rg "\-\-animate-pulse\b" rg "\-\-animate-bounce\b" rg "\-\-blur-xs\b" rg "\-\-blur-sm\b" rg "\-\-blur-lg\b" rg "\-\-blur-2xl\b" rg "\-\-blur-3xl\b" rg "\-\-perspective-dramatic\b" rg "\-\-perspective-near\b" rg "\-\-perspective-normal\b" rg "\-\-perspective-midrange\b" rg "\-\-perspective-distant\b" rg "\-\-aspect-video\b" ``` </details> The only exception I noticed is that we have this: ```css src/typography.utilities.css 10: @media (width >= theme(--breakpoint-sm)) { ``` But this is not a variable, but it's replaced at build time with the actual value, so this is not a real issue. Testing on other templates: <img width="2968" alt="image" src="https://github.com/user-attachments/assets/cabf121d-4cb9-468f-9cf5-ceb02609dc7d" /> Fixes: https://github.com/tailwindlabs/tailwindcss/issues/16145 --------- Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2025-02-07 18:12:47 +01:00
".custom-css {
color: red;
}"
`)
})