web design uiNovember 5, 20267 min read

CSS 渐变颜色:为什么渐变中间会变灰,以及 3 种修复方法

把蓝色渐变到黄色,中间会变灰,因为十六进制颜色是按 RGB 混合的。加一个中间色标、用 OKLCH 混合,或者选色轮上相邻的颜色。附 5 个可直接用的渐变。

By Boone
XLinkedIn
CSS Gradient Colors: Why Gradients Turn Gray in the Middle and 3 Ways to Fix It

渐变中间会变灰,是因为浏览器按 RGB 混合十六进制颜色,而两种处于对立位置的颜色在中点会互相抵消。解决办法是有意给中间指定一个颜色,或者改变混合的计算方式。下面是三种修复方法和五个可以直接粘贴的渐变。

为什么中间会变灰

看一个看起来脏兮兮的渐变,先别管两端。两端没问题,那是你选的。中间才是没人选的部分。

渐变就是混合,混合就需要数学。十六进制颜色就是 RGB 值,所以浏览器默认逐个通道去混合。

在蓝色和黄色的中点,红色在 0 和 255 之间取一半,绿色在 0 和 255 之间取一半,蓝色在 255 和 0 之间取一半。每个通道都落在 128 附近。红、绿、蓝相等,就是灰色的定义。

#0000FF 到 #FFFF00

一个从蓝色到黄色的渐变,中间变成一片平淡的灰色

加上 #0EBAAE 中间色标

同样的蓝到黄渐变,中间是青绿色,整条渐变都保持着鲜艳
两端完全相同。左边的混合直接穿过 #808080。右边的中间是青绿色,所以整个渐变从头到尾都是活的。

这不是你的显示器问题,也不是压缩问题。这是算术,只要两种颜色在色轮上相距很远就会出现。蓝色和黄色几乎是完全相反的,这是最糟的情况。

修复 1:加一个中间色标

最直接的办法,就是别再把中间交给运气。在 50% 处加第三个色标,用你自己挑的颜色。

css
background: linear-gradient(90deg, #0000FF, #0EBAAE, #FFFF00);

#0EBAAE 是一种青绿色,在视觉上位于蓝色和黄色之间。现在混合变成蓝到青绿,再从青绿到黄,两半都不会经过灰色。

这在所有浏览器里都能用,也不需要新语法,所以对必须处处一致的设计来说是稳妥之选。用眼睛挑中间色,然后把它和两端放在一起比一比。代价是你现在要管三个颜色,而不是两个。

修复 2:用 OKLCH 混合

另一种办法是改变数学,而不是加颜色。CSS 允许你选择混合发生的色彩空间,而 OKLCH 用明度、色度和色相来描述颜色。色度就是颜色有多鲜艳,所以保持色度的混合就会保持鲜艳。

css
background: linear-gradient(in oklch, #0000FF, #FFFF00);

加上 in oklch 后,浏览器会绕着色轮走,经过绿色和青绿色,而不是直接穿过灰色的中心。你仍然只有两个颜色,代码也很短。MDN 把它记录为渐变函数里的颜色插值方法,而传统的十六进制颜色在你不指定时只用 RGB,是为了兼容老页面。

有两点要知道。这一路上有些颜色可能超出屏幕能显示的范围,所以浏览器会把它们裁剪到最接近的可显示值。另外,它走的是绕色轮的短路径,所以要检查它选的路径是不是你喜欢的。我们的指南 现代 CSS 中的 OKLCH 颜色 对这个色彩空间讲得更深入。

修复 3:选相邻的颜色

第三种办法完全不碰代码。它选的是不会互相抵消的颜色。

#0066FF 到 #FF8800

一个从蓝色到橙色的渐变,中间变成暗淡的棕灰色

#6440E0 到 #E040A0

一个从紫罗兰色到粉色的渐变,整条都保持明亮
蓝色和橙色是对立色,所以在中间碰上一片暗淡的 #807780。紫罗兰和粉色是邻居,所以在中间碰上浓郁的 #A240C0。

对立色混合成灰色。邻近色混合成介于两者之间、仍然有颜色的东西。如果品牌就是要搭配两个对立色,你仍然可以把它们用在渐变里:在它们之间加一个中间色标,或者用 OKLCH 混合。

蓝到橙,默认混合

中间是棕灰色的蓝到橙渐变

蓝到橙,用 oklch

同样的蓝到橙渐变,用 OKLCH 混合,经过紫罗兰和粉色而不是灰色
两端和之前一样,只改了混合方式。灰色没了,中间是明亮的粉色。

如何检查你自己的渐变

  1. 看中间,不要看两端。
  2. 说出你在那里看到的颜色名。如果名字是灰、棕或泥色,比如 #808080 或 #807780,那就是问题所在。
  3. 从上面挑一种修复方法,把两个版本并排比较。

渐变的好坏取决于它最差的那一点,而最差的那一点几乎总是中间。

五个可以直接拿走的渐变

每一个都检查过,中间保持着颜色。第一个内置了中间色标。另外四个使用相邻色相。点一下代码即可复制。

一个从蓝色经青绿色到黄色的渐变
蓝、青绿、黄。点一下颜色即可复制代码。
一个从紫罗兰色到粉色的渐变
紫罗兰到粉色。点一下颜色即可复制代码。
一个从蓝色到青绿色的渐变
蓝色到青绿色。点一下颜色即可复制代码。
一个从橙色到艳粉色的渐变
橙色到艳粉色。点一下颜色即可复制代码。
一个从绿色到青柠色的渐变
绿色到青柠色。点一下颜色即可复制代码。
渐变起点中间终点为什么有效
蓝、青绿、黄#0000FF#0EBAAE#FFFF00两端是对立色,靠真正的中间色标救场
紫罗兰到粉色#6440E0无#E040A0色轮上的邻居
蓝色到青绿色#2F5BEA无#14B8A6色轮上的邻居
橙色到艳粉色#FF7A00无#FF2E93色轮上的邻居
绿色到青柠色#00A86B无#C6F432色轮上的邻居

把这个交给你的开发者

css
.gradient-sunrise { background: linear-gradient(90deg, #0000FF, #0EBAAE, #FFFF00); } .gradient-violet { background: linear-gradient(90deg, #6440E0, #E040A0); } .gradient-ocean { background: linear-gradient(90deg, #2F5BEA, #14B8A6); } .gradient-sunset { background: linear-gradient(90deg, #FF7A00, #FF2E93); } .gradient-meadow { background: linear-gradient(90deg, #00A86B, #C6F432); } /* Two opposite colors, no middle stop: choose the blend space instead. */ .gradient-opposites { background: linear-gradient(in oklch, #0066FF, #FF8800); }

如果浏览器不认识 in oklch,它会忽略整条声明。先写一行普通的 linear-gradient(...) 作为回退,再在后面写 OKLCH 那一行。

FAQ

为什么我的渐变中间会变灰?

十六进制颜色按 RGB 混合,而在色轮上相距很远的两种颜色平均下来就是灰色。蓝色 #0000FF 和黄色 #FFFF00 会在 #808080 相遇。

如何避免 CSS 渐变看起来脏?

加一个带真实颜色的中间色标,用 linear-gradient(in oklch, ...) 以 OKLCH 混合,或者选两个在色轮上相邻的颜色。

CSS 渐变里的 "in oklch" 是做什么的?

它告诉浏览器在 OKLCH 色彩空间而不是 RGB 中混合颜色,所以中间保持颜色,而不是掉到灰色。

哪些渐变颜色搭配起来好看?

色轮上的邻居,比如紫罗兰 #6440E0 到粉色 #E040A0,或者绿色 #00A86B 到青柠色 #C6F432。它们的混合从头到尾都保持明亮。

所有浏览器都支持 OKLCH 渐变吗?

现代浏览器支持,但不支持的浏览器会丢掉这条声明。在它前面加一行普通渐变作为回退。

为什么蓝到黄会变灰而不是绿色?

因为混合走的是穿过 RGB 的直线路径,两者的平均值就是灰色。只有当你把绿色加为色标,或者用 OKLCH 混合时,中间才会出现绿色。

来源

  • CSS Color Module Level 4, interpolation:十六进制等传统 sRGB 颜色默认在 sRGB 中插值,其他空间通过颜色插值方法来选择。
  • MDN, linear-gradient():<color-interpolation-method> 语法,in oklch。
  • MDN, OKLCH color:明度、色度和色相。
  • (0, 0, 255) 和 (255, 255, 0) 的中点是 (127.5, 127.5, 127.5),即 #808080,OKLCH 色度为 0。#0066FF 到 #FF8800 的中点 (#807780) 和 #6440E0 到 #E040A0 的中点 (#A240C0) 是我们在 sRGB 中计算的。本页的色条根据这些计算渲染,OKLCH 色条会像浏览器一样裁剪超出屏幕范围的颜色。
  • 最初作为轮播图发布于 UX Brainy。

Want gradients, color and every other detail designed as one system? Our team designs and builds product UI that holds up on every screen.

Get Started

More from Brainy Papers

Keep reading