Skip to content

Commit d6d913e

Browse files
Don't use color-mix(…) on currentColor (#17247)
Closes #17194 This PR works around a crash when rendering opacity on `currentColor` (as used by the placeholder styles in preflight) on Safari 16.4 and Safari 16.5. Unfortunately it seems that the [`color-mix(…)` function is not compatible with `currentColor` for these versions of Safari](https://stackoverflow.com/questions/76436497/the-color-mix-property-involving-currentcolor-causes-safari-to-crash). We tried a few different ways to work around this without success: - Using an `@supports` media query to target these Safari versions and overwriting the placeholder still makes these browsers crash. - Changing the way we apply opacity to `currentColor` in core doesn't seem to work for non-placeholder values: #17194 (comment) However, a wrong opacity is still better than a complete browser crash. The work-around of using the `oklab(…)` function does seem to work for `::placeholder` styles in preflight though according to our testing so this PR applies this change to preflight. ## Test plan - See https://play.tailwindcss.com/WSsSTLHu8h?file=css - Tested on Chrome/Safari 16.4/Safari 18.3/Firefox <img width="564" alt="Screenshot 2025-03-17 at 11 32 47" src="https://github.com/user-attachments/assets/cfd0db71-f39a-4bc0-bade-cea70afe50ae" />
1 parent 4489493 commit d6d913e

File tree

8 files changed

+54
-38
lines changed

8 files changed

+54
-38
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222

2323
- Fix incorrect angle in `-bg-conic-*` utilities ([#17174](https://github.com/tailwindlabs/tailwindcss/pull/17174))
2424
- Fix `border-[12px_4px]` being interpreted as a `border-color` instead of a `border-width` ([#17248](https://github.com/tailwindlabs/tailwindcss/pull/17248))
25+
- Use the `oklab(…)` function when applying opacity to `currentColor` to work around a crash in Safari 16.4 and 16.5 ([#17247](https://github.com/tailwindlabs/tailwindcss/pull/17247))
2526

2627
## [4.0.14] - 2025-03-13
2728

integrations/vite/astro.test.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ test(
1919
import { defineConfig } from 'astro/config'
2020
2121
// https://astro.build/config
22-
export default defineConfig({ vite: { plugins: [tailwindcss()] } })
22+
export default defineConfig({
23+
vite: { plugins: [tailwindcss()] },
24+
build: { inlineStylesheets: 'never' },
25+
})
2326
`,
2427
'src/pages/index.astro': html`
2528
<div class="underline">Hello, world!</div>
@@ -90,8 +93,13 @@ test(
9093
import { defineConfig } from 'astro/config'
9194
9295
// https://astro.build/config
93-
export default defineConfig({ vite: { plugins: [tailwindcss()] }, integrations: [react()] })
96+
export default defineConfig({
97+
vite: { plugins: [tailwindcss()] },
98+
integrations: [react()],
99+
build: { inlineStylesheets: 'never' },
100+
})
94101
`,
102+
// prettier-ignore
95103
'src/pages/index.astro': html`
96104
---
97105
import ClientOnly from './client-only';

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ exports[`\`@import 'tailwindcss'\` is replaced with the generated CSS 1`] = `
169169
170170
::placeholder {
171171
opacity: 1;
172-
color: color-mix(in oklab, currentColor 50%, transparent);
172+
color: oklab(from currentColor l a b / 50%);
173173
}
174174
175175
textarea {

packages/tailwindcss/preflight.css

+2-2
Original file line numberDiff line numberDiff line change
@@ -285,12 +285,12 @@ textarea,
285285

286286
/*
287287
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
288-
2. Set the default placeholder color to a semi-transparent version of the current text color.
288+
2. Set the default placeholder color to a semi-transparent version of the current text color. We use the `oklab(…)` function to work around an issue in Safari 16.4 and 16.5. (https://github.com/tailwindlabs/tailwindcss/issues/17194)
289289
*/
290290

291291
::placeholder {
292292
opacity: 1; /* 1 */
293-
color: color-mix(in oklab, currentColor 50%, transparent); /* 2 */
293+
color: oklab(from currentColor l a b / 50%); /* 2 */
294294
}
295295

296296
/*

packages/tailwindcss/src/__snapshots__/utilities.test.ts.snap

+9-9
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ exports[`border-* 1`] = `
104104
}
105105
106106
.border-current\\/50 {
107-
border-color: color-mix(in oklab, currentColor 50%, transparent);
107+
border-color: oklab(from currentColor l a b / 50%);
108108
}
109109
110110
.border-inherit {
@@ -246,7 +246,7 @@ exports[`border-b-* 1`] = `
246246
}
247247
248248
.border-b-current\\/50 {
249-
border-bottom-color: color-mix(in oklab, currentColor 50%, transparent);
249+
border-bottom-color: oklab(from currentColor l a b / 50%);
250250
}
251251
252252
.border-b-inherit {
@@ -388,7 +388,7 @@ exports[`border-e-* 1`] = `
388388
}
389389
390390
.border-e-current\\/50 {
391-
border-inline-end-color: color-mix(in oklab, currentColor 50%, transparent);
391+
border-inline-end-color: oklab(from currentColor l a b / 50%);
392392
}
393393
394394
.border-e-inherit {
@@ -530,7 +530,7 @@ exports[`border-l-* 1`] = `
530530
}
531531
532532
.border-l-current\\/50 {
533-
border-left-color: color-mix(in oklab, currentColor 50%, transparent);
533+
border-left-color: oklab(from currentColor l a b / 50%);
534534
}
535535
536536
.border-l-inherit {
@@ -672,7 +672,7 @@ exports[`border-r-* 1`] = `
672672
}
673673
674674
.border-r-current\\/50 {
675-
border-right-color: color-mix(in oklab, currentColor 50%, transparent);
675+
border-right-color: oklab(from currentColor l a b / 50%);
676676
}
677677
678678
.border-r-inherit {
@@ -814,7 +814,7 @@ exports[`border-s-* 1`] = `
814814
}
815815
816816
.border-s-current\\/50 {
817-
border-inline-start-color: color-mix(in oklab, currentColor 50%, transparent);
817+
border-inline-start-color: oklab(from currentColor l a b / 50%);
818818
}
819819
820820
.border-s-inherit {
@@ -956,7 +956,7 @@ exports[`border-t-* 1`] = `
956956
}
957957
958958
.border-t-current\\/50 {
959-
border-top-color: color-mix(in oklab, currentColor 50%, transparent);
959+
border-top-color: oklab(from currentColor l a b / 50%);
960960
}
961961
962962
.border-t-inherit {
@@ -1098,7 +1098,7 @@ exports[`border-x-* 1`] = `
10981098
}
10991099
11001100
.border-x-current\\/50 {
1101-
border-inline-color: color-mix(in oklab, currentColor 50%, transparent);
1101+
border-inline-color: oklab(from currentColor l a b / 50%);
11021102
}
11031103
11041104
.border-x-inherit {
@@ -1240,7 +1240,7 @@ exports[`border-y-* 1`] = `
12401240
}
12411241
12421242
.border-y-current\\/50 {
1243-
border-block-color: color-mix(in oklab, currentColor 50%, transparent);
1243+
border-block-color: oklab(from currentColor l a b / 50%);
12441244
}
12451245
12461246
.border-y-inherit {

packages/tailwindcss/src/compat/plugin-api.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3860,7 +3860,7 @@ describe('matchUtilities()', () => {
38603860
}
38613861
38623862
.scrollbar-current\\/45 {
3863-
scrollbar-color: color-mix(in oklab, currentColor 45%, transparent);
3863+
scrollbar-color: oklab(from currentColor l a b / 45%);
38643864
}"
38653865
`)
38663866
})

packages/tailwindcss/src/utilities.test.ts

+23-23
Original file line numberDiff line numberDiff line change
@@ -7984,7 +7984,7 @@ test('accent', async () => {
79847984
}
79857985
79867986
.accent-current\\/50, .accent-current\\/\\[0\\.5\\], .accent-current\\/\\[50\\%\\] {
7987-
accent-color: color-mix(in oklab, currentColor 50%, transparent);
7987+
accent-color: oklab(from currentColor l a b / 50%);
79887988
}
79897989
79907990
.accent-inherit {
@@ -8099,7 +8099,7 @@ test('caret', async () => {
80998099
}
81008100
81018101
.caret-current\\/50, .caret-current\\/\\[0\\.5\\], .caret-current\\/\\[50\\%\\] {
8102-
caret-color: color-mix(in oklab, currentColor 50%, transparent);
8102+
caret-color: oklab(from currentColor l a b / 50%);
81038103
}
81048104
81058105
.caret-inherit {
@@ -8212,7 +8212,7 @@ test('divide-color', async () => {
82128212
}
82138213
82148214
:where(.divide-current\\/50 > :not(:last-child)), :where(.divide-current\\/\\[0\\.5\\] > :not(:last-child)), :where(.divide-current\\/\\[50\\%\\] > :not(:last-child)) {
8215-
border-color: color-mix(in oklab, currentColor 50%, transparent);
8215+
border-color: oklab(from currentColor l a b / 50%);
82168216
}
82178217
82188218
:where(.divide-inherit > :not(:last-child)) {
@@ -10144,11 +10144,11 @@ test('bg', async () => {
1014410144
}
1014510145
1014610146
.bg-current\\/50, .bg-current\\/\\[0\\.5\\], .bg-current\\/\\[50\\%\\] {
10147-
background-color: color-mix(in oklab, currentColor 50%, transparent);
10147+
background-color: oklab(from currentColor l a b / 50%);
1014810148
}
1014910149
1015010150
.bg-current\\/\\[var\\(--bg-opacity\\)\\] {
10151-
background-color: color-mix(in oklab, currentColor var(--bg-opacity), transparent);
10151+
background-color: oklab(from currentColor l a b / var(--bg-opacity));
1015210152
}
1015310153
1015410154
.bg-inherit {
@@ -10666,11 +10666,11 @@ test('bg', async () => {
1066610666
),
1066710667
).toMatchInlineSnapshot(`
1066810668
".bg-current\\/custom {
10669-
background-color: color-mix(in oklab, currentColor var(--opacity-custom, var(--custom-opacity)), transparent);
10669+
background-color: oklab(from currentColor l a b / var(--opacity-custom, var(--custom-opacity)));
1067010670
}
1067110671
1067210672
.bg-current\\/half {
10673-
background-color: color-mix(in oklab, currentColor var(--opacity-half, .5), transparent);
10673+
background-color: oklab(from currentColor l a b / var(--opacity-half, .5));
1067410674
}
1067510675
1067610676
.\\[color\\:red\\]\\/half {
@@ -10764,7 +10764,7 @@ test('from', async () => {
1076410764
}
1076510765
1076610766
.from-current\\/50, .from-current\\/\\[0\\.5\\], .from-current\\/\\[50\\%\\] {
10767-
--tw-gradient-from: color-mix(in oklab, currentColor 50%, transparent);
10767+
--tw-gradient-from: oklab(from currentColor l a b / 50%);
1076810768
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
1076910769
}
1077010770
@@ -10990,7 +10990,7 @@ test('via', async () => {
1099010990
}
1099110991
1099210992
.via-current\\/50, .via-current\\/\\[0\\.5\\], .via-current\\/\\[50\\%\\] {
10993-
--tw-gradient-via: color-mix(in oklab, currentColor 50%, transparent);
10993+
--tw-gradient-via: oklab(from currentColor l a b / 50%);
1099410994
--tw-gradient-via-stops: var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);
1099510995
--tw-gradient-stops: var(--tw-gradient-via-stops);
1099610996
}
@@ -11212,7 +11212,7 @@ test('to', async () => {
1121211212
}
1121311213
1121411214
.to-current\\/50, .to-current\\/\\[0\\.5\\], .to-current\\/\\[50\\%\\] {
11215-
--tw-gradient-to: color-mix(in oklab, currentColor 50%, transparent);
11215+
--tw-gradient-to: oklab(from currentColor l a b / 50%);
1121611216
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
1121711217
}
1121811218
@@ -11739,7 +11739,7 @@ test('fill', async () => {
1173911739
}
1174011740
1174111741
.fill-current\\/50, .fill-current\\/\\[0\\.5\\], .fill-current\\/\\[50\\%\\] {
11742-
fill: color-mix(in oklab, currentColor 50%, transparent);
11742+
fill: oklab(from currentColor l a b / 50%);
1174311743
}
1174411744
1174511745
.fill-inherit {
@@ -11876,7 +11876,7 @@ test('stroke', async () => {
1187611876
}
1187711877
1187811878
.stroke-current\\/50, .stroke-current\\/\\[0\\.5\\], .stroke-current\\/\\[50\\%\\] {
11879-
stroke: color-mix(in oklab, currentColor 50%, transparent);
11879+
stroke: oklab(from currentColor l a b / 50%);
1188011880
}
1188111881
1188211882
.stroke-inherit {
@@ -12852,7 +12852,7 @@ test('placeholder', async () => {
1285212852
}
1285312853
1285412854
.placeholder-current\\/50::placeholder, .placeholder-current\\/\\[0\\.5\\]::placeholder, .placeholder-current\\/\\[50\\%\\]::placeholder {
12855-
color: color-mix(in oklab, currentColor 50%, transparent);
12855+
color: oklab(from currentColor l a b / 50%);
1285612856
}
1285712857
1285812858
.placeholder-inherit::placeholder {
@@ -13001,9 +13001,9 @@ test('decoration', async () => {
1300113001
}
1300213002
1300313003
.decoration-current\\/50, .decoration-current\\/\\[0\\.5\\], .decoration-current\\/\\[50\\%\\] {
13004-
-webkit-text-decoration-color: color-mix(in oklab, currentColor 50%, transparent);
13005-
-webkit-text-decoration-color: color-mix(in oklab, currentColor 50%, transparent);
13006-
text-decoration-color: color-mix(in oklab, currentColor 50%, transparent);
13004+
-webkit-text-decoration-color: oklab(from currentColor l a b / 50%);
13005+
-webkit-text-decoration-color: oklab(from currentColor l a b / 50%);
13006+
text-decoration-color: oklab(from currentColor l a b / 50%);
1300713007
}
1300813008
1300913009
.decoration-inherit {
@@ -14706,7 +14706,7 @@ test('outline', async () => {
1470614706
}
1470714707
1470814708
.outline-current\\/50, .outline-current\\/\\[0\\.5\\], .outline-current\\/\\[50\\%\\] {
14709-
outline-color: color-mix(in oklab, currentColor 50%, transparent);
14709+
outline-color: oklab(from currentColor l a b / 50%);
1471014710
}
1471114711
1471214712
.outline-inherit {
@@ -15156,7 +15156,7 @@ test('text', async () => {
1515615156
}
1515715157
1515815158
.text-current\\/50, .text-current\\/\\[0\\.5\\], .text-current\\/\\[50\\%\\] {
15159-
color: color-mix(in oklab, currentColor 50%, transparent);
15159+
color: oklab(from currentColor l a b / 50%);
1516015160
}
1516115161
1516215162
.text-inherit {
@@ -15325,7 +15325,7 @@ test('shadow', async () => {
1532515325
}
1532615326
1532715327
.shadow-current\\/50, .shadow-current\\/\\[0\\.5\\], .shadow-current\\/\\[50\\%\\] {
15328-
--tw-shadow-color: color-mix(in oklab, currentColor 50%, transparent);
15328+
--tw-shadow-color: oklab(from currentColor l a b / 50%);
1532915329
}
1533015330
1533115331
.shadow-inherit {
@@ -15547,7 +15547,7 @@ test('inset-shadow', async () => {
1554715547
}
1554815548
1554915549
.inset-shadow-current\\/50, .inset-shadow-current\\/\\[0\\.5\\], .inset-shadow-current\\/\\[50\\%\\] {
15550-
--tw-inset-shadow-color: color-mix(in oklab, currentColor 50%, transparent);
15550+
--tw-inset-shadow-color: oklab(from currentColor l a b / 50%);
1555115551
}
1555215552
1555315553
.inset-shadow-inherit {
@@ -15785,7 +15785,7 @@ test('ring', async () => {
1578515785
}
1578615786
1578715787
.ring-current\\/50, .ring-current\\/\\[0\\.5\\], .ring-current\\/\\[50\\%\\] {
15788-
--tw-ring-color: color-mix(in oklab, currentColor 50%, transparent);
15788+
--tw-ring-color: oklab(from currentColor l a b / 50%);
1578915789
}
1579015790
1579115791
.ring-inherit {
@@ -16124,7 +16124,7 @@ test('inset-ring', async () => {
1612416124
}
1612516125
1612616126
.inset-ring-current\\/50, .inset-ring-current\\/\\[0\\.5\\], .inset-ring-current\\/\\[50\\%\\] {
16127-
--tw-inset-ring-color: color-mix(in oklab, currentColor 50%, transparent);
16127+
--tw-inset-ring-color: oklab(from currentColor l a b / 50%);
1612816128
}
1612916129
1613016130
.inset-ring-inherit {
@@ -16368,7 +16368,7 @@ test('ring-offset', async () => {
1636816368
}
1636916369
1637016370
.ring-offset-current\\/50, .ring-offset-current\\/\\[0\\.5\\], .ring-offset-current\\/\\[50\\%\\] {
16371-
--tw-ring-offset-color: color-mix(in oklab, currentColor 50%, transparent);
16371+
--tw-ring-offset-color: oklab(from currentColor l a b / 50%);
1637216372
}
1637316373
1637416374
.ring-offset-inherit {

packages/tailwindcss/src/utilities.ts

+7
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,13 @@ export function withAlpha(value: string, alpha: string): string {
136136
alpha = `${alphaAsNumber * 100}%`
137137
}
138138

139+
// Use the `oklab(…)` function when applying alpha to `currentColor` to work
140+
// around a crash with Safari 16.4 and 16.5
141+
// https://github.com/tailwindlabs/tailwindcss/issues/17194
142+
if (value === 'currentColor') {
143+
return `oklab(from currentColor l a b / ${alpha})`
144+
}
145+
139146
return `color-mix(in oklab, ${value} ${alpha}, transparent)`
140147
}
141148

0 commit comments

Comments
 (0)