无需设计师帮助的配色方案


当然,您中的很多人都处于需要快速挑选颜色进行装饰的情况,而设计师在心情不好或度假时正忙于执行更重要的任务。这项任务并不困难,但是有时您必须等待几天的答案。

我叫Emil Frolov,是DomKlik内部服务团队的一名技术人员。在本文中,我将告诉您图书馆的想法是如何诞生的,现在可以节省很多选择颜色的时间。该解决方案很简单,但是非常有用,可以投入使用。

特别是如果您需要为深色方案选择颜色。

任务


DomKlik有一个公司门户,其每个部分都有其自己的配色方案。以前,要创建一个新的部分,每次都要折磨设计师并要求他们挑选一套新的颜色并将其转移到界面上时。事实证明,大量的额外代码花费了大量时间在通信,等待和协调上。我真的想简化并加快整个过程。

我们在Internet上寻找现成的解决方案,但没有找到合适的解决方案。然后,我们决定编写一个库:输入设计师提供的颜色(品牌),然后库选择一些其他合适的颜色。我们还希望该库也生成深色方案。
这不是幸福的秘诀,而是每个人都可以在其项目框架内发展的想法。您可以在此处看到一个小型演示

想法与解决方案


我们考虑了如何做。我们从基于基本的颜色生成算法开始。在您的这些Internet上,仍然找不到任何准备。但是他们发现了一个可以更改不同颜色设置

许多人都知道有很多不同的颜色匹配算法:



我看不出要画它们的任何意义,他们已经在我之前完成了数百次。但是有一些关键点:

  1. 对我们来说,它们是多余的。
  2. 我想为自己选择颜色。

因此,设计人员和开发人员合并为一个冲动,决定一次手动选择该方案。

首先,我们描述了基本颜色:

export const getColors = (projectColor, inverse) => {
  ...
  const BASE_SUCCESS = '#00985f';
  const BASE_WARNING = '#ff9900';
  const BASE_PROGRESS = '#fe5c05';
  const BASE_ALERT = '#ff3333';
  const BASE_SYSTEM = '#778a9b';
  const BASE_NORMAL = '#dde3e5';
  const BASE_WHITE = '#ffffff';
  const BASE_BLACK = '#000';
  const TYPO_BASE_BLACK = '#242629';
  const TYPO_LINK = '#33BDFF';
  ...
}

基于此,您可以开始创建。我们得到用于基本颜色的对象。

  import color from 'color-js';

  export const getColors = (projectColor, inverse) => {
    ...
    const baseWhite = color(BASE_WHITE);
    const baseBlack = color(BASE_BLACK);
    const baseTypoBlack = color(TYPO_BASE_BLACK);
    ...
  }

我认为完全描述所有颜色选择没有任何意义,但举例来说,我将给出几行:

export const getColors = (projectColor, inverse) => {
  ...
  const bgBrand = baseProject;
  const bgHard = baseColor.setLightness(0.4);
  const bgSharp = baseColor.setLightness(0.18);
  const bgStripe = baseColor.setLightness(0.1);
  const bgGhost = baseColor.setLightness(0.07);
  ...
}

选择完原色后,我们面临以下问题。

元素上的文字显示什么颜色?

这项任务并不像看起来那样困难。要从十六进制值求解它,我们需要获取元素的亮度。我们使用两个辅助函数来完成此操作。第一种将十六进制转换为RGB:

const hexToRgb = (hex) => {
  const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  const newHex = hex.replace(shorthandRegex, (
    magenta,
    red,
    green,
    blue
  ) => red + red + green + green + blue + blue);

  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(newHex);

  return result ? {
    red: parseInt(result[1], 16),
    green: parseInt(result[2], 16),
    blue: parseInt(result[3], 16)
  } : null;
};

RGB的第二个功能获取背景的亮度,并确定颜色是深色还是浅色:

export const getBgTextColor = (bgColor) => {
  const rgb = hexToRgb(bgColor);
  const light = (rgb.red * 0.8 + rgb.green + rgb.blue * 0.2) / 510 * 100;

  return light > 70 ? '#000000' : '#ffffff';
};

您可能会认为现在一切都准备就绪,可以进行下一步了。但是,不,我们仍然想要开箱即用地支持深色主题吗?是! 我们想要!

您可能已经注意到我们向函数传递了一个标志inverse让我们考虑一下此标志来稍微更改代码:

import color from 'color-js';

export const getColors = (projectColor, inverse) => {
  ...
  const BASE_SUCCESS = '#00985f';
  const BASE_WARNING = '#ff9900';
  const BASE_PROGRESS = '#fe5c05';
  const BASE_ALERT = '#ff3333';
  const BASE_SYSTEM = '#778a9b';
  const BASE_NORMAL = '#dde3e5';
  const BASE_WHITE = '#ffffff';
  const BASE_BLACK = '#000';
  const TYPO_BASE_BLACK = '#242629';
  const TYPO_LINK = '#33BDFF';

  ...

  const baseWhite = color(BASE_WHITE);
  const baseBlack = color(BASE_BLACK);
  const baseTypoBlack = color(TYPO_BASE_BLACK);
  const baseColor = inverse ? baseWhite : baseBlack;
  const typoColor = inverse ? baseWhite : baseTypoBlack;

  ...

  const bgHard = inverse ? baseColor.setLightness(0.4) : baseColor.lightenByAmount(0.85);
  const bgSharp = inverse ? baseColor.setLightness(0.18) : baseColor.lightenByAmount(0.95);
  const bgStripe = inverse ? baseColor.setLightness(0.1) : baseColor.lightenByAmount(0.96);
  const bgGhost = inverse ? baseColor.setLightness(0.07) : baseColor.lightenByAmount(0.99);

  ...
}

就这样。我们可以给出一个颜色列表:

return {
  ...
    // BG
    'color-bg-hard': bgHard.toString(),
    'color-bg-sharp': bgSharp.toString(),
    'color-bg-stripe': bgStripe.toString(),
    'color-bg-ghost': bgGhost.toString(),
    'color-bg-primary': bgDefault.toString(),
  ...
}

在两天内,在设计师的帮助下,我创建了一个库,该库在输出时提供了用于深色和浅色主题的调色板。

下一个问题:如何使用?

很简单。为了实现生成的配色方案,我们通过样式块使用了CSS变量的插入。这样可以避免与其他CSS库使用的CSS变量发生冲突。

  const colors = getColors(color, themeKey === 'dark');
  const colorsVars = Object.keys(colors).map((key) => `--${key}: ${customColors[key]}`).join(';');
  
  const link = document.createElement('style');
  const headTag = document.getElementsByTagName('head')[0];

  link.type = 'text/css';
  link.id = 'project-theme-scope';
  const stylesBody = `:root {${colorsVars}}`;

  link.innerText = stylesBody;

  headTag.append(link);

而现在最美味了。注意注意!现在,只需几行,当我们为一半的元素添加深色主题支持时:

  body {
    background: var(--color-bg-ghost);
    color: var(--color-typo-primary);
  }

结果是一个库,我们在其中传递主要品牌颜色并获得一组CSS变量,然后将其用于为项目着色。

大部分时间都花在选择配色方案上。我必须手动对一堆不同的参数进行排序,以使颜色相互组合。但是现在,在为门户的新部分选择颜色的每次迭代中,我们节省了几天的时间。

由于设计人员参与了算法的创建,因此仍然没有出现他对库生成的颜色不满意的情况。是的,配色方案不是太大,很难出错。

我再次强调,我们并不是声称这是唯一正确的决定。这个想法已经实现,并且效果很好。我试图向您介绍要点,实现的细节和范围仅取决于您和您的项目。

谢谢您的关注。

All Articles