色板生成
在做组件库的时候,我很好奇色板是怎么产生。于是我询问了我的设计师朋友,她听到我的问题,从抽屉里拿出一本讲述调色的书。指着书本中密密麻麻的色块,和我说先找出主题色,然后再用颜色原理和经验一点点调整出来衍生色。我感叹这位设计师朋友的经验丰富。但我也能否通过代码就能自动生成好看的色板。
翻阅了一些颜色的书和其他的组件库代码,我发现好看的色板的确可以用代码生成出来。我收藏了这篇来自 JINGWHALE(后称为 JW) 的文章 产品设计系统之动态色彩体系研究 。这篇文章总结了大部分颜色生成思路:
- 通过 HSV(HSL)可以更好的生成色板
- 色相(H)可以在区分冷软色的情况使用相邻色
- 饱和度(S)和明度(L)可以使用动态梯度来定义而非线性改变
作为技术博客,我整理一些源码。方便前端程序员理解他们在说什么,或是怎么做。
转化 RGB 到 HSV
(下方转自 Acro Design 的使用)很简单就是 RGB 三通道对 HSV 的转换,这里的公式挺巧妙的可以推敲一下。
export var hsvToRgb = function (h, s, v) {
var i = Math.floor(h * 6);
var f = h * 6 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
var mod = i % 6;
var r = [v, q, p, p, t, v][mod];
var g = [t, v, v, q, p, p][mod];
var b = [p, p, t, v, v, q][mod];
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255),
};
};
export var rgbToHsv = function (r, g, b) {
r /= 255;
g /= 255;
b /= 255;
var max = Math.max(r, g, b);
var min = Math.min(r, g, b);
var h = 0;
var v = max;
var d = max - min;
var s = max === 0 ? 0 : d / max;
if (max === min) {
h = 0;
}
else {
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
default:
break;
}
h /= 6;
}
return { h: h, s: s, v: v };
};
色相和临近色
色相生成很有趣,Acro Design 的步长(hueStep)使用 2。其原理和 JW 的逻辑类似。整个色带分为暖色和冷色带。在暖色带执行加法(亮色模式),冷色带做减法。如 JW 在文中提供的色相规则。
让调色板各个颜色之间要有一定的差异性,并且色彩梯度要柔和自然;HSV动态调色板算法,以基准色为中心,通过遍历浅色区个数、深色区位个数,循环构建同色系调调色板的色彩
1)、调色板的颜色个数定为10,1-4序号位为浅色区衍生色,5序号位为基准色,6-10序号位为深色区衍生色(本文将基于基准色生成的色彩叫做衍生色);
据此我们可以写一段小代码
function generateHue(light, i) {
let hue;
if (h >= 60 && h <= 240) {
// 亮色中间做减法
hue = light ? h - hueStep * i : h + hueStep * i;
} else {
// 两侧做加法
hue = light ? h + hueStep * i : h - hueStep * i;
}
// 反转成圈
if (hue < 0) {
hue += 360;
} else if (hue >= 360) {
hue -= 360;
}
return Math.round(hue);
}
绝大多数人应该和我一样觉得色系应该是同一个色相。不过邻近色的使用在保证色彩和谐的情况下,增加的色相变化,的确让人觉得更加有趣
类比色/邻近色(Analogous Colors)是指在色轮上相邻的颜色。通常,这些颜色之间的色相差异较小,因此它们看起来非常和谐和自然。
诚然我们无法定义「和谐」与「有趣」,但我想把「和谐」归于「有规律」,「有趣」理解为「变化」。那么我认为「有规律的变化」是一种美的体现。
动态梯度改变
对于饱和度(S)和明度(L)的处理,使用贝塞尔曲线10等分,相对于部分使用线性变化的组件库来说。的确是个有趣的处理方式。虽然我不太能理解这里使用贝塞尔来做曲率的理论基础是什么,但设计的唯一评判就是视觉!。
// 这里直接摘自 JW 的源码
function generateVValue(isLight, hsv, i){ //isLight是否为浅色区,hsv为基准色,i为当前衍生色的序号位
// 计算H动态梯度值
var VValue = ""
var point = i * (1/baseEasingPointSetp);
var VEasing = bezierEasing(VBezier);
var dynamicStepV = VEasing(point)*((VMax-VMin)/baseEasingPointSetp)
// 计算衍生色V值
if (isLight) {
VValue = hsv.v + dynamicStepV * i;
} else {
VValue = hsv.v - dynamicStepV * i;
}
// 修正衍生色V值
if (VValue > 1) {
VValue = 1;
}
return SValue;
}
上述是我对自动生成色板的研究。像实现自动定义色板或是复用色板生成代码的,可以参考一下 Acro Design 团队的代码。我觉得非常有启发性。
对齐
作为一个强迫症患者(非重度),没对齐真的是一眼就看出来的。但怎样才能对齐呢?我们会谈论视觉重量和对齐。网上有很多优秀的文章和设计原理,大家可以搜搜看。我简单聊聊我的理解
- 视觉为主,找三到四个同事或朋友。大家觉得对齐了就是对齐了。而不是扣着 align-items 等配置不放。
- 视觉大小和图片的大小是两码事。视觉大小和中心点由将画面模糊后由得到椭圆形的大小和中心点替代。
- 对齐一定是中心锚点对齐而不是左对齐,上对齐。
前端同学可以关注的点
对于【 「 等中文字符,保持良好的缩进更重要。因为普通字符一般都是半角。全角字符往往会显得很突兀尤其在句首这里会让人觉得没有对齐。
p[title^=\300c],
p[title^=\300e],
p[title^=\3010], h3[title^=\300c]
h3[title^=\300e], h3[title^=\3010] {
text-indent:-0.6em;
}
锚点改变,可以通过 Transform-origin 改变对象的对齐点。这个属性对于对齐还是挺有作用的。