Skip to content

Commit 98c279d

Browse files
Don't create bare spacing utilities with invalid multiples (#14962)
Closes #14960 When we moved to the `--spacing` multiples scale, we seemingly overlooked a bail that caused us to use non-numerical values as a spacing multiple. This caused the `-translate-x-full` and `-translate-y-full` utilities to treat `full` as a valid multiple in our spacing scale and created invalid CSS: ```css .-translate-x-full { --tw-translate-x: calc(var(--spacing) * -x-full); --tw-translate-y: calc(var(--spacing) * -x-full); translate: var(--tw-translate-x) var(--tw-translate-y); } ``` ## Test plan I reproduced the issue in our Vite playground and then created a failing test case. It requires a `--spacing` `@theme` variable to be defined so I've added this as a test case now in the unit tests. I also audited all places that are using `calc()` and wrapping some numbers. In doing so I found a few other broken cases: - `-translate-x-full` - `-translate-y-full` - `-space-x-full` - `-space-y-full` - `-inset-full` I validated that the fix indeed works and no longer creates broken CSS definitions for these cases: <kbd><img width="1405" alt="Screenshot 2024-11-11 at 19 33 51" src="https://github.com/user-attachments/assets/99072112-9ed4-4456-bad8-5679679e7198"></kbd> --------- Co-authored-by: Adam Wathan <[email protected]>
1 parent 50d7355 commit 98c279d

File tree

4 files changed

+156
-0
lines changed

4 files changed

+156
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Fixed
1111

1212
- Don't reset horizontal padding on date/time pseudo-elements ([#14959](https://github.com/tailwindlabs/tailwindcss/pull/14959))
13+
- Don't emit `calc()` with invalid values for bare values that aren't integers in spacing utilities ([#14962](https://github.com/tailwindlabs/tailwindcss/pull/14962))
1314

1415
## [4.0.0-alpha.32] - 2024-11-11
1516

packages/tailwindcss/src/utilities.test.ts

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3861,6 +3861,82 @@ test('translate-x', async () => {
38613861
'-translate-x-[var(--value)]/foo',
38623862
]),
38633863
).toEqual('')
3864+
3865+
expect(
3866+
await compileCss(
3867+
css`
3868+
@theme {
3869+
--spacing: 0.25rem;
3870+
}
3871+
@tailwind utilities;
3872+
`,
3873+
['translate-x-full', '-translate-x-full', 'translate-x-px', '-translate-x-[var(--value)]'],
3874+
),
3875+
).toMatchInlineSnapshot(`
3876+
":root {
3877+
--spacing: .25rem;
3878+
}
3879+
3880+
.-translate-x-\\[var\\(--value\\)\\] {
3881+
--tw-translate-x: calc(var(--value) * -1);
3882+
translate: var(--tw-translate-x) var(--tw-translate-y);
3883+
}
3884+
3885+
.-translate-x-full {
3886+
--tw-translate-x: -100%;
3887+
translate: var(--tw-translate-x) var(--tw-translate-y);
3888+
}
3889+
3890+
.translate-x-full {
3891+
--tw-translate-x: 100%;
3892+
translate: var(--tw-translate-x) var(--tw-translate-y);
3893+
}
3894+
3895+
.translate-x-px {
3896+
--tw-translate-x: 1px;
3897+
translate: var(--tw-translate-x) var(--tw-translate-y);
3898+
}
3899+
3900+
@supports (-moz-orient: inline) {
3901+
@layer base {
3902+
*, :before, :after, ::backdrop {
3903+
--tw-translate-x: 0;
3904+
--tw-translate-y: 0;
3905+
--tw-translate-z: 0;
3906+
}
3907+
}
3908+
}
3909+
3910+
@property --tw-translate-x {
3911+
syntax: "<length> | <percentage>";
3912+
inherits: false;
3913+
initial-value: 0;
3914+
}
3915+
3916+
@property --tw-translate-y {
3917+
syntax: "<length> | <percentage>";
3918+
inherits: false;
3919+
initial-value: 0;
3920+
}
3921+
3922+
@property --tw-translate-z {
3923+
syntax: "<length>";
3924+
inherits: false;
3925+
initial-value: 0;
3926+
}"
3927+
`)
3928+
expect(
3929+
await run([
3930+
'perspective',
3931+
'-perspective',
3932+
'perspective-potato',
3933+
'perspective-123',
3934+
'perspective-normal/foo',
3935+
'perspective-dramatic/foo',
3936+
'perspective-none/foo',
3937+
'perspective-[456px]/foo',
3938+
]),
3939+
).toEqual('')
38643940
})
38653941

38663942
test('translate-y', async () => {
@@ -3933,6 +4009,82 @@ test('translate-y', async () => {
39334009
'-translate-y-[var(--value)]/foo',
39344010
]),
39354011
).toEqual('')
4012+
4013+
expect(
4014+
await compileCss(
4015+
css`
4016+
@theme {
4017+
--spacing: 0.25rem;
4018+
}
4019+
@tailwind utilities;
4020+
`,
4021+
['translate-y-full', '-translate-y-full', 'translate-y-px', '-translate-y-[var(--value)]'],
4022+
),
4023+
).toMatchInlineSnapshot(`
4024+
":root {
4025+
--spacing: .25rem;
4026+
}
4027+
4028+
.-translate-y-\\[var\\(--value\\)\\] {
4029+
--tw-translate-y: calc(var(--value) * -1);
4030+
translate: var(--tw-translate-x) var(--tw-translate-y);
4031+
}
4032+
4033+
.-translate-y-full {
4034+
--tw-translate-y: -100%;
4035+
translate: var(--tw-translate-x) var(--tw-translate-y);
4036+
}
4037+
4038+
.translate-y-full {
4039+
--tw-translate-y: 100%;
4040+
translate: var(--tw-translate-x) var(--tw-translate-y);
4041+
}
4042+
4043+
.translate-y-px {
4044+
--tw-translate-y: 1px;
4045+
translate: var(--tw-translate-x) var(--tw-translate-y);
4046+
}
4047+
4048+
@supports (-moz-orient: inline) {
4049+
@layer base {
4050+
*, :before, :after, ::backdrop {
4051+
--tw-translate-x: 0;
4052+
--tw-translate-y: 0;
4053+
--tw-translate-z: 0;
4054+
}
4055+
}
4056+
}
4057+
4058+
@property --tw-translate-x {
4059+
syntax: "<length> | <percentage>";
4060+
inherits: false;
4061+
initial-value: 0;
4062+
}
4063+
4064+
@property --tw-translate-y {
4065+
syntax: "<length> | <percentage>";
4066+
inherits: false;
4067+
initial-value: 0;
4068+
}
4069+
4070+
@property --tw-translate-z {
4071+
syntax: "<length>";
4072+
inherits: false;
4073+
initial-value: 0;
4074+
}"
4075+
`)
4076+
expect(
4077+
await run([
4078+
'perspective',
4079+
'-perspective',
4080+
'perspective-potato',
4081+
'perspective-123',
4082+
'perspective-normal/foo',
4083+
'perspective-dramatic/foo',
4084+
'perspective-none/foo',
4085+
'perspective-[456px]/foo',
4086+
]),
4087+
).toEqual('')
39364088
})
39374089

39384090
test('translate-z', async () => {

packages/tailwindcss/src/utilities.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,8 @@ export function createUtilities(theme: Theme) {
387387
handleNegativeBareValue: ({ value }) => {
388388
let multiplier = theme.resolve(null, ['--spacing'])
389389
if (!multiplier) return null
390+
if (!isValidSpacingMultiplier(value)) return null
391+
390392
return `calc(${multiplier} * -${value})`
391393
},
392394
handle,

playgrounds/vite/src/app.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export function App() {
22
return (
33
<div className="m-3 p-3 border">
44
<h1 className="text-blue-500">Hello World</h1>
5+
<div className="-inset-x-full -inset-y-full -space-x-full -space-y-full -inset-full"></div>
56
</div>
67
)
78
}

0 commit comments

Comments
 (0)