关于 Grabient
Grabient 用关键帧生成渐变:2 到 8 种颜色,由一条平滑曲线连接。
1 · 关键帧
关键帧是你选择的颜色。和动画一样,你设定几个关键帧,它们之间的颜色会自动补全。一个调色板有 2 到 8 个关键帧,沿渐变均匀分布,渐变会经过每一个关键帧:
每个关键帧是 OKLCH 中的三个数值。明度 L 从 0(黑)到 1(白)。彩度 C 表示颜色有多鲜艳:0 是灰色,屏幕上最鲜艳的颜色约为 0.3。色相 H 是色轮上的角度,单位为度。
2 · 公式
明度、彩度和色相各有一条曲线,绘制在上方的图表中。每条曲线都经过各个关键帧,并在关键帧之间平滑弯曲。任一点的颜色,就是三条曲线在该点的读数。
CSS 和 Figma 渐变用直线连接色标,因此在过渡节奏变化的地方可能出现一道淡淡的边缘。
公式中,t 从渐变起点的 0 变到终点的 1。有 K 个关键帧时,第 i 个关键帧位于 t = i / (K − 1)(从 0 开始计数)。每条曲线都是 Catmull–Rom 样条,gamut() 让颜色适配屏幕(第 6 节):
color(t) = gamut( L(t), C(t), H(t) )
// one axis: a Catmull–Rom spline through K evenly spaced valuesconst { min, max, floor } = Math;function spline(v, t) { const K = v.length, x = min(max(t, 0), 1) * (K - 1); const i = min(K - 2, floor(x)), u = x - i; const p0 = v[max(i - 1, 0)], p1 = v[i]; const p2 = v[i + 1], p3 = v[min(i + 2, K - 1)]; return p1 + 0.5 * u * (p2 - p0 + u * (2*p0 - 5*p1 + 4*p2 - p3 + u * (3*(p1 - p2) + p3 - p0)));}// the color at t from the keyframes' L, C and H. A spline can overshoot// between keyframes, so L is kept in 0..1 and C at 0 or more. The// browser fits an oklch() color to the screen (section 6).function color(L, C, H, t) { const l = min(max(spline(L, t), 0), 1), c = max(spline(C, t), 0); return `oklch(${l} ${c} ${spline(H, t)})`;}3 · 步数
绘制渐变时,Grabient 在均匀分布的点上取色,这些点称为“步”。第一步和最后一步就是第一个和最后一个关键帧。渐变样式把各步用作色标。色块样式把每一步显示为一块纯色。步数永远不少于关键帧数:
4 · 为什么用 OKLCH
RGB 和 HSL 描述的是屏幕如何混合光线,它们的数值常常与我们看到的不符。纯黄和纯蓝的 HSL 明度都是 50%,但黄色看起来亮得多。OKLCH 给它们的值是 0.97 和 0.45。它是 Björn Ottosson 的 OKLab 的极坐标形式,设计目标是让数值上相等的变化看起来也相等。两种颜色用两种方式混合:
由于明度、彩度和色相相互独立,改变关键帧的色相时,它的明度保持不变。
5 · 超过 360° 的色相
在两个色相之间,渐变可以沿色轮朝任一方向绕行,大多数工具会选较短的那一边。Grabient 允许色相超过 360°:690° 和 330° 是同一种颜色,只是多绕了一圈。渐变会走完全程:
调色板的色相行程是最后一个色相减去第一个色相,绕过的整圈也计算在内,因此一道完整彩虹的行程为 360°。相邻关键帧最多可相差 540°。
6 · 屏幕无法显示的颜色
OKLCH 能描述比屏幕所能显示的更鲜艳的颜色。对于这些颜色,Grabient 会保留明度和色相,降低彩度,直到颜色落入色域:标准屏幕上是 sRGB,广色域屏幕上是 Display P3。CSS Color 4 对 oklch() 颜色也是这样处理的:
7 · 配方
几个调色板,以及构成它们的曲线:
反转把关键帧按相反的顺序排列。反相生成负片:每个明度 L 变为 1 − L,每个色相旋转 180°。
8 · 种子
每个调色板的地址都包含它的种子,即其关键帧的简短编码。第一张图的种子是 kW6iw33i87sY6O2wq7rmZ07I。
种子是 k 后接按位打包的关键帧:明度 8 位,彩度 8 位,第一个色相 9 位,之后每个色相 10 位,存储为与前一个色相的差值:
两个关键帧生成 11 个字符的种子,八个关键帧生成 37 个字符的种子。每个调色板恰好有一个种子。
由十六进制颜色设定的关键帧会以 24 位精确保留该颜色。这样的种子长度为 9 到 50 个字符。