Skip to content

Commit efae52c

Browse files
akxRobinMalfait
andauthored
Simplify CSS when using utilities that use a *-0 or *-1 value (#20196)
## Why? While inspecting a Tailwind-powered site, I noticed selectors like ```css .inset-0{inset:calc(var(--spacing) * 0)} .inset-x-0{inset-inline:calc(var(--spacing) * 0)} .top-0{top:calc(var(--spacing) * 0)} ``` which seem a bit silly, not to mention more complex for the end-user device parsing the CSS. ## Summary This PR adjusts helpers to not generate `calc(... * 0)` expressions. #19095 does a similar thing on CSS AST, but that doesn't run during the build proper. ## Test plan Ran `pnpm build && pnpm test && pnpm test:integration`. (Some unrelated tests failed on my machine, hopefully less in CI.) --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
1 parent 0c5f8bf commit efae52c

5 files changed

Lines changed: 531 additions & 176 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2525
- Ensure `@tailwindcss/cli` in `--watch` mode recovers when a tracked dependency is deleted and restored ([#20137](https://github.com/tailwindlabs/tailwindcss/pull/20137))
2626
- Ensure standalone `@tailwindcss/cli` binaries are ignored when scanning for class candidates ([#20139](https://github.com/tailwindlabs/tailwindcss/pull/20139))
2727

28+
### Changed
29+
30+
- Generate `0` instead of `calc(var(--spacing) * 0)` for spacing utilities like `m-0` and `left-0` ([#20196](https://github.com/tailwindlabs/tailwindcss/pull/20196))
31+
- Generate `var(--spacing)` instead of `calc(var(--spacing) * 1)` for spacing utilities like `m-1` and `left-1` ([#20196](https://github.com/tailwindlabs/tailwindcss/pull/20196))
32+
2833
## [4.3.0] - 2026-05-08
2934

3035
### Added

packages/tailwindcss/src/css-functions.test.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,100 @@ describe('--spacing(…)', () => {
105105
`)
106106
})
107107

108+
describe('optimizations', () => {
109+
test('--spacing(…) optimizes the output when the input is `0`', async () => {
110+
expect(
111+
await compileCss(css`
112+
@theme {
113+
--spacing: 0.25rem;
114+
}
115+
116+
.foo {
117+
margin: --spacing(0);
118+
padding: --spacing(0px);
119+
}
120+
`),
121+
).toMatchInlineSnapshot(`
122+
"
123+
.foo {
124+
margin: 0;
125+
padding: 0;
126+
}
127+
"
128+
`)
129+
})
130+
131+
test('--spacing(…) optimizes the output when the input is `0` (with an inlined theme value)', async () => {
132+
expect(
133+
await compileCss(css`
134+
@theme inline {
135+
--spacing: 0.25rem;
136+
}
137+
138+
.foo {
139+
margin: --spacing(0);
140+
padding: --spacing(0px);
141+
}
142+
`),
143+
).toMatchInlineSnapshot(`
144+
"
145+
.foo {
146+
margin: 0;
147+
padding: 0;
148+
}
149+
"
150+
`)
151+
})
152+
153+
test('--spacing(…) optimizes the output when the input is `1`', async () => {
154+
expect(
155+
await compileCss(css`
156+
@theme {
157+
--spacing: 0.25rem;
158+
}
159+
160+
.foo {
161+
margin: --spacing(1);
162+
padding: --spacing(1px);
163+
}
164+
`),
165+
).toMatchInlineSnapshot(`
166+
"
167+
:root, :host {
168+
--spacing: .25rem;
169+
}
170+
171+
.foo {
172+
margin: var(--spacing);
173+
padding: var(--spacing);
174+
}
175+
"
176+
`)
177+
})
178+
179+
test('--spacing(…) optimizes the output when the input is `1` (with an inlined theme value)', async () => {
180+
expect(
181+
await compileCss(css`
182+
@theme inline {
183+
--spacing: 0.25rem;
184+
}
185+
186+
.foo {
187+
margin: --spacing(1);
188+
padding: --spacing(1px);
189+
}
190+
`),
191+
).toMatchInlineSnapshot(`
192+
"
193+
.foo {
194+
margin: .25rem;
195+
padding: .25rem;
196+
}
197+
"
198+
`)
199+
})
200+
})
201+
108202
test('--spacing(…) relies on `--spacing` to be defined', async () => {
109203
await expect(() =>
110204
compileCss(css`

packages/tailwindcss/src/css-functions.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Features } from '.'
22
import { type AstNode } from './ast'
33
import type { DesignSystem } from './design-system'
44
import { withAlpha } from './utilities'
5+
import { dimensions } from './utils/dimensions'
56
import { segment } from './utils/segment'
67
import * as ValueParser from './value-parser'
78
import { walk, WalkAction } from './walk'
@@ -62,6 +63,22 @@ function spacing(
6263
)
6364
}
6465

66+
// Optimization:
67+
//
68+
// - We know that at this point the `--spacing` value must be set.
69+
// - We know that `--spacing` must be set to a `<length>` unit, such as `0.25rem`
70+
// - We can assume that the `--spacing` value is not set to a `0`-like value.
71+
// Otherwise `p-<anything>` would calculate as `0` which wouldn't make sense.
72+
//
73+
// - That means that a value of `0` can be replaced by `0`
74+
// - That means that a value of `1` can be replaced by `multiplier`
75+
let valueDimension = dimensions.get(value)
76+
if (valueDimension) {
77+
if (valueDimension[0] === 0) return '0'
78+
if (valueDimension[0] === 1) return multiplier
79+
}
80+
81+
// No known optimizations available, use full calculation
6582
return `calc(${multiplier} * ${value})`
6683
}
6784

0 commit comments

Comments
 (0)