Interpolate gradients using OKLCH by default (#14708)
This PR updates all of our gradient utilities to interpolate using OKLCH by default instead of sRGB. This results in a smoother transition between colors that preserves saturation throughout the gradient, rather than hitting the dreaded dull gray zone in between your color stops. Here are a few examples comparing sRGB (top) to OKLCH (bottom): <img width="736" alt="image" src="https://github.com/user-attachments/assets/57a158b6-a3a2-4eda-813e-1b596c7d4b3a"> We only apply a default interpolation mode when _not_ using arbitrary values with the gradient utility. Simplified but clear: ```css .bg-linear-to-r { background-image: linear-gradient(to right in oklch, var(--gradient-color-stops)); } .bg-linear-[to_right] { background-image: linear-gradient(to right, var(--gradient-color-stops)); } .bg-linear-[to_right_in_hsl] { background-image: linear-gradient(to right in hsl, var(--gradient-color-stops)); } ``` --------- Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This commit is contained in:
parent
72c30d422a
commit
edb066e0aa
4 changed files with 50 additions and 43 deletions
|
|
@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- Add first draft of new wide-gamut color palette ([#14693](https://github.com/tailwindlabs/tailwindcss/pull/14693))
|
||||
- Support linear gradient angles as bare values ([#14707](https://github.com/tailwindlabs/tailwindcss/pull/14707))
|
||||
- Interpolate gradients in OKLCH by default ([#14708](https://github.com/tailwindlabs/tailwindcss/pull/14708))
|
||||
- _Upgrade (experimental)_: Migrate `theme(…)` calls to `var(…)` or to the modern `theme(…)` syntax ([#14664](https://github.com/tailwindlabs/tailwindcss/pull/14664), [#14695](https://github.com/tailwindlabs/tailwindcss/pull/14695))
|
||||
|
||||
### Fixed
|
||||
|
|
|
|||
|
|
@ -9557,8 +9557,8 @@ test('bg', async () => {
|
|||
}
|
||||
|
||||
.-bg-linear-45 {
|
||||
--tw-gradient-position: calc(45deg * -1), ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops, calc(45deg * -1)));
|
||||
--tw-gradient-position: calc(45deg * -1) in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.-bg-linear-\\[1\\.3rad\\] {
|
||||
|
|
@ -9572,48 +9572,48 @@ test('bg', async () => {
|
|||
}
|
||||
|
||||
.bg-gradient-to-b {
|
||||
--tw-gradient-position: to bottom, ;
|
||||
--tw-gradient-position: to bottom in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-gradient-to-bl {
|
||||
--tw-gradient-position: to bottom left, ;
|
||||
--tw-gradient-position: to bottom left in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-gradient-to-br {
|
||||
--tw-gradient-position: to bottom right, ;
|
||||
--tw-gradient-position: to bottom right in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-gradient-to-l {
|
||||
--tw-gradient-position: to left, ;
|
||||
--tw-gradient-position: to left in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-gradient-to-r {
|
||||
--tw-gradient-position: to right, ;
|
||||
--tw-gradient-position: to right in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-gradient-to-t {
|
||||
--tw-gradient-position: to top, ;
|
||||
--tw-gradient-position: to top in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-gradient-to-tl {
|
||||
--tw-gradient-position: to top left, ;
|
||||
--tw-gradient-position: to top left in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-gradient-to-tr {
|
||||
--tw-gradient-position: to top right, ;
|
||||
--tw-gradient-position: to top right in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-linear-45 {
|
||||
--tw-gradient-position: 45deg, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops, 45deg));
|
||||
--tw-gradient-position: 45deg in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-linear-\\[1\\.3rad\\] {
|
||||
|
|
@ -9632,42 +9632,42 @@ test('bg', async () => {
|
|||
}
|
||||
|
||||
.bg-linear-to-b {
|
||||
--tw-gradient-position: to bottom, ;
|
||||
--tw-gradient-position: to bottom in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-linear-to-bl {
|
||||
--tw-gradient-position: to bottom left, ;
|
||||
--tw-gradient-position: to bottom left in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-linear-to-br {
|
||||
--tw-gradient-position: to bottom right, ;
|
||||
--tw-gradient-position: to bottom right in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-linear-to-l {
|
||||
--tw-gradient-position: to left, ;
|
||||
--tw-gradient-position: to left in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-linear-to-r {
|
||||
--tw-gradient-position: to right, ;
|
||||
--tw-gradient-position: to right in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-linear-to-t {
|
||||
--tw-gradient-position: to top, ;
|
||||
--tw-gradient-position: to top in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-linear-to-tl {
|
||||
--tw-gradient-position: to top left, ;
|
||||
--tw-gradient-position: to top left in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
.bg-linear-to-tr {
|
||||
--tw-gradient-position: to top right, ;
|
||||
--tw-gradient-position: to top right in oklch, ;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2516,12 +2516,12 @@ export function createUtilities(theme: Theme) {
|
|||
['tl', 'top left'],
|
||||
]) {
|
||||
staticUtility(`bg-gradient-to-${value}`, [
|
||||
['--tw-gradient-position', `to ${direction},`],
|
||||
['--tw-gradient-position', `to ${direction} in oklch,`],
|
||||
['background-image', `linear-gradient(var(--tw-gradient-stops))`],
|
||||
])
|
||||
|
||||
staticUtility(`bg-linear-to-${value}`, [
|
||||
['--tw-gradient-position', `to ${direction},`],
|
||||
['--tw-gradient-position', `to ${direction} in oklch,`],
|
||||
['background-image', `linear-gradient(var(--tw-gradient-stops))`],
|
||||
])
|
||||
}
|
||||
|
|
@ -2558,8 +2558,8 @@ export function createUtilities(theme: Theme) {
|
|||
value = withNegative(`${value}deg`, candidate)
|
||||
|
||||
return [
|
||||
decl('--tw-gradient-position', `${value},`),
|
||||
decl('background-image', `linear-gradient(var(--tw-gradient-stops,${value}))`),
|
||||
decl('--tw-gradient-position', `${value} in oklch,`),
|
||||
decl('background-image', `linear-gradient(var(--tw-gradient-stops))`),
|
||||
]
|
||||
}
|
||||
})
|
||||
|
|
@ -2569,7 +2569,7 @@ export function createUtilities(theme: Theme) {
|
|||
|
||||
if (!candidate.value) {
|
||||
return [
|
||||
decl('--tw-gradient-position', `initial`),
|
||||
decl('--tw-gradient-position', `in oklch,`),
|
||||
decl('background-image', `conic-gradient(var(--tw-gradient-stops))`),
|
||||
]
|
||||
}
|
||||
|
|
@ -2587,7 +2587,7 @@ export function createUtilities(theme: Theme) {
|
|||
value = withNegative(`${value}deg`, candidate)
|
||||
|
||||
return [
|
||||
decl('--tw-gradient-position', `from ${value},`),
|
||||
decl('--tw-gradient-position', `from ${value} in oklch,`),
|
||||
decl('background-image', `conic-gradient(var(--tw-gradient-stops))`),
|
||||
]
|
||||
}
|
||||
|
|
@ -2598,7 +2598,7 @@ export function createUtilities(theme: Theme) {
|
|||
|
||||
if (!candidate.value) {
|
||||
return [
|
||||
decl('--tw-gradient-position', `initial`),
|
||||
decl('--tw-gradient-position', `in oklch,`),
|
||||
decl('background-image', `radial-gradient(var(--tw-gradient-stops))`),
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,37 +30,40 @@ test('touch action', async ({ page }) => {
|
|||
for (let [classes, expected] of [
|
||||
[
|
||||
'bg-linear-to-r from-red',
|
||||
'linear-gradient(to right, rgb(255, 0, 0) 0%, rgba(0, 0, 0, 0) 100%)',
|
||||
'linear-gradient(to right in oklch, rgb(255, 0, 0) 0%, rgba(0, 0, 0, 0) 100%)',
|
||||
],
|
||||
[
|
||||
'bg-linear-to-r via-red',
|
||||
'linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(255, 0, 0) 50%, rgba(0, 0, 0, 0) 100%)',
|
||||
'linear-gradient(to right in oklch, rgba(0, 0, 0, 0) 0%, rgb(255, 0, 0) 50%, rgba(0, 0, 0, 0) 100%)',
|
||||
],
|
||||
[
|
||||
'bg-linear-to-r to-red',
|
||||
'linear-gradient(to right in oklch, rgba(0, 0, 0, 0) 0%, rgb(255, 0, 0) 100%)',
|
||||
],
|
||||
['bg-linear-to-r to-red', 'linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(255, 0, 0) 100%)'],
|
||||
[
|
||||
'bg-linear-to-r from-red to-blue',
|
||||
'linear-gradient(to right, rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
'linear-gradient(to right in oklch, rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
],
|
||||
[
|
||||
'bg-linear-45 from-red to-blue',
|
||||
'linear-gradient(45deg, rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
'linear-gradient(45deg in oklch, rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
],
|
||||
[
|
||||
'-bg-linear-45 from-red to-blue',
|
||||
// Chrome reports a different (but also correct) computed value than Firefox/WebKit so we check
|
||||
// for both options.
|
||||
[
|
||||
'linear-gradient(-45deg, rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
'linear-gradient(calc(-45deg), rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
'linear-gradient(-45deg in oklch, rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
'linear-gradient(calc(-45deg) in oklch, rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
],
|
||||
],
|
||||
[
|
||||
'bg-linear-to-r via-red to-blue',
|
||||
'linear-gradient(to right, rgba(0, 0, 0, 0) 0%, rgb(255, 0, 0) 50%, rgb(0, 0, 255) 100%)',
|
||||
'linear-gradient(to right in oklch, rgba(0, 0, 0, 0) 0%, rgb(255, 0, 0) 50%, rgb(0, 0, 255) 100%)',
|
||||
],
|
||||
[
|
||||
'bg-linear-to-r from-red via-green to-blue',
|
||||
'linear-gradient(to right, rgb(255, 0, 0) 0%, rgb(0, 255, 0) 50%, rgb(0, 0, 255) 100%)',
|
||||
'linear-gradient(to right in oklch, rgb(255, 0, 0) 0%, rgb(0, 255, 0) 50%, rgb(0, 0, 255) 100%)',
|
||||
],
|
||||
[
|
||||
'bg-linear-[to_right,var(--color-red),var(--color-green),var(--color-blue)]',
|
||||
|
|
@ -88,13 +91,13 @@ test('background gradient, going from 2 to 3', async ({ page }) => {
|
|||
)
|
||||
|
||||
expect(await getPropertyValue('#x', 'background-image')).toEqual(
|
||||
'linear-gradient(to right, rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
'linear-gradient(to right in oklch, rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
)
|
||||
|
||||
await page.locator('#x').hover()
|
||||
|
||||
expect(await getPropertyValue('#x', 'background-image')).toEqual(
|
||||
'linear-gradient(to right, rgb(255, 0, 0) 0%, rgb(0, 255, 0) 50%, rgb(0, 0, 255) 100%)',
|
||||
'linear-gradient(to right in oklch, rgb(255, 0, 0) 0%, rgb(0, 255, 0) 50%, rgb(0, 0, 255) 100%)',
|
||||
)
|
||||
})
|
||||
|
||||
|
|
@ -109,19 +112,22 @@ test('background gradient, going from 3 to 2', async ({ page }) => {
|
|||
)
|
||||
|
||||
expect(await getPropertyValue('#x', 'background-image')).toEqual(
|
||||
'linear-gradient(to right, rgb(255, 0, 0) 0%, rgb(0, 255, 0) 50%, rgb(0, 0, 255) 100%)',
|
||||
'linear-gradient(to right in oklch, rgb(255, 0, 0) 0%, rgb(0, 255, 0) 50%, rgb(0, 0, 255) 100%)',
|
||||
)
|
||||
|
||||
await page.locator('#x').hover()
|
||||
|
||||
expect(await getPropertyValue('#x', 'background-image')).toEqual(
|
||||
'linear-gradient(to right, rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
'linear-gradient(to right in oklch, rgb(255, 0, 0) 0%, rgb(0, 0, 255) 100%)',
|
||||
)
|
||||
})
|
||||
|
||||
for (let [classes, expected] of [
|
||||
['bg-conic from-red', 'conic-gradient(rgb(255, 0, 0) 0%, rgba(0, 0, 0, 0) 100%)'],
|
||||
['bg-conic-45 from-red', 'conic-gradient(from 45deg, rgb(255, 0, 0) 0%, rgba(0, 0, 0, 0) 100%)'],
|
||||
['bg-conic from-red', 'conic-gradient(in oklch, rgb(255, 0, 0) 0%, rgba(0, 0, 0, 0) 100%)'],
|
||||
[
|
||||
'bg-conic-45 from-red',
|
||||
'conic-gradient(from 45deg in oklch, rgb(255, 0, 0) 0%, rgba(0, 0, 0, 0) 100%)',
|
||||
],
|
||||
[
|
||||
'bg-conic-[from_45deg] from-red',
|
||||
'conic-gradient(from 45deg, rgb(255, 0, 0) 0%, rgba(0, 0, 0, 0) 100%)',
|
||||
|
|
@ -142,7 +148,7 @@ for (let [classes, expected] of [
|
|||
}
|
||||
|
||||
for (let [classes, expected] of [
|
||||
['bg-radial from-red', 'radial-gradient(rgb(255, 0, 0) 0%, rgba(0, 0, 0, 0) 100%)'],
|
||||
['bg-radial from-red', 'radial-gradient(in oklch, rgb(255, 0, 0) 0%, rgba(0, 0, 0, 0) 100%)'],
|
||||
[
|
||||
'bg-radial-[at_0%_0%] from-red',
|
||||
'radial-gradient(at 0% 0%, rgb(255, 0, 0) 0%, rgba(0, 0, 0, 0) 100%)',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue