CSS 渐变颜色:为什么渐变中间会变灰,以及 3 种修复方法
把蓝色渐变到黄色,中间会变灰,因为十六进制颜色是按 RGB 混合的。加一个中间色标、用 OKLCH 混合,或者选色轮上相邻的颜色。附 5 个可直接用的渐变。

渐变中间会变灰,是因为浏览器按 RGB 混合十六进制颜色,而两种处于对立位置的颜色在中点会互相抵消。解决办法是有意给中间指定一个颜色,或者改变混合的计算方式。下面是三种修复方法和五个可以直接粘贴的渐变。
为什么中间会变灰
看一个看起来脏兮兮的渐变,先别管两端。两端没问题,那是你选的。中间才是没人选的部分。
渐变就是混合,混合就需要数学。十六进制颜色就是 RGB 值,所以浏览器默认逐个通道去混合。
在蓝色和黄色的中点,红色在 0 和 255 之间取一半,绿色在 0 和 255 之间取一半,蓝色在 255 和 0 之间取一半。每个通道都落在 128 附近。红、绿、蓝相等,就是灰色的定义。
#0000FF 到 #FFFF00

加上 #0EBAAE 中间色标

这不是你的显示器问题,也不是压缩问题。这是算术,只要两种颜色在色轮上相距很远就会出现。蓝色和黄色几乎是完全相反的,这是最糟的情况。
修复 1:加一个中间色标
最直接的办法,就是别再把中间交给运气。在 50% 处加第三个色标,用你自己挑的颜色。
background: linear-gradient(90deg, #0000FF, #0EBAAE, #FFFF00);
#0EBAAE 是一种青绿色,在视觉上位于蓝色和黄色之间。现在混合变成蓝到青绿,再从青绿到黄,两半都不会经过灰色。
这在所有浏览器里都能用,也不需要新语法,所以对必须处处一致的设计来说是稳妥之选。用眼睛挑中间色,然后把它和两端放在一起比一比。代价是你现在要管三个颜色,而不是两个。
修复 2:用 OKLCH 混合
另一种办法是改变数学,而不是加颜色。CSS 允许你选择混合发生的色彩空间,而 OKLCH 用明度、色度和色相来描述颜色。色度就是颜色有多鲜艳,所以保持色度的混合就会保持鲜艳。
background: linear-gradient(in oklch, #0000FF, #FFFF00);
加上 in oklch 后,浏览器会绕着色轮走,经过绿色和青绿色,而不是直接穿过灰色的中心。你仍然只有两个颜色,代码也很短。MDN 把它记录为渐变函数里的颜色插值方法,而传统的十六进制颜色在你不指定时只用 RGB,是为了兼容老页面。
有两点要知道。这一路上有些颜色可能超出屏幕能显示的范围,所以浏览器会把它们裁剪到最接近的可显示值。另外,它走的是绕色轮的短路径,所以要检查它选的路径是不是你喜欢的。我们的指南 现代 CSS 中的 OKLCH 颜色 对这个色彩空间讲得更深入。
修复 3:选相邻的颜色
第三种办法完全不碰代码。它选的是不会互相抵消的颜色。
#0066FF 到 #FF8800

#6440E0 到 #E040A0

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

蓝到橙,用 oklch

如何检查你自己的渐变
- 看中间,不要看两端。
- 说出你在那里看到的颜色名。如果名字是灰、棕或泥色,比如 #808080 或 #807780,那就是问题所在。
- 从上面挑一种修复方法,把两个版本并排比较。
渐变的好坏取决于它最差的那一点,而最差的那一点几乎总是中间。
五个可以直接拿走的渐变
每一个都检查过,中间保持着颜色。第一个内置了中间色标。另外四个使用相邻色相。点一下代码即可复制。





| 渐变 | 起点 | 中间 | 终点 | 为什么有效 |
|---|---|---|---|---|
| 蓝、青绿、黄 | #0000FF | #0EBAAE | #FFFF00 | 两端是对立色,靠真正的中间色标救场 |
| 紫罗兰到粉色 | #6440E0 | 无 | #E040A0 | 色轮上的邻居 |
| 蓝色到青绿色 | #2F5BEA | 无 | #14B8A6 | 色轮上的邻居 |
| 橙色到艳粉色 | #FF7A00 | 无 | #FF2E93 | 色轮上的邻居 |
| 绿色到青柠色 | #00A86B | 无 | #C6F432 | 色轮上的邻居 |
把这个交给你的开发者
.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




