Esquema de cores sem a ajuda de um designer


Certamente muitos de vocês estão em uma situação em que precisam escolher rapidamente as cores para decoração, e o designer está ocupado com tarefas mais importantes, de mau humor ou de férias. A tarefa não é difícil, mas às vezes você precisa esperar por uma resposta por vários dias.

Meu nome é Emil Frolov, sou técnico da equipe de serviços internos da DomKlik. Neste artigo, mostrarei como nasceu a idéia de uma biblioteca, que agora economiza muito tempo na escolha das cores. A solução é simples, mas muito útil, coloque-a em serviço.

Especialmente se você precisar escolher cores para o esquema escuro.

Tarefa


O DomKlik possui um portal corporativo, cada seção com seu próprio esquema de cores. Anteriormente, para criar uma nova seção, cada vez que eu tinha que atormentar os designers e pedir-lhes para pegar um novo conjunto de cores e transferi-los para a interface. Ele produziu uma quantidade enorme de código extra, gastou muito tempo em correspondência, espera e coordenação. Eu realmente queria simplificar e acelerar todo o processo.

Procuramos soluções prontas na Internet, mas nada foi encontrado. E então eles decidiram escrever uma biblioteca: você insere a cor (marca) que o designer fornece e a biblioteca seleciona algumas cores mais adequadas. Também queríamos que a biblioteca gerasse esquemas de cores escuras.
Esta não é uma receita para a felicidade, mas uma ideia que todos podem desenvolver dentro da estrutura de seu projeto. Você pode ver uma pequena demonstração aqui .

Idéia e solução


Nós pensamos em como fazê-lo. Começamos com um algoritmo básico de geração de cores. Nestas suas Internet novamente, nada de pronto foi encontrado. Mas eles encontraram uma biblioteca que pode alterar configurações de cores diferentes.

Muitas pessoas sabem que existem muitos algoritmos de correspondência de cores diferentes:



não vejo sentido em pintá-los, eles já fizeram isso centenas de vezes antes de mim. Mas existem alguns pontos-chave:

  1. Para nós, eles são redundantes.
  2. Eu queria escolher cores para mim.

Portanto, o designer e o desenvolvedor, fundidos em um único impulso, decidiram retomar o esquema manualmente uma vez.

Para começar, descrevemos as cores básicas:

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';
  ...
}

Com base nisso, você pode começar a criar. Temos objetos para trabalhar com cores básicas.

  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);
    ...
  }

Acho que não faz sentido descrever completamente toda a seleção de cores, mas, por exemplo, darei algumas linhas:

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);
  ...
}

Depois que terminamos de escolher as cores primárias, enfrentamos o seguinte problema.

E que cor exibe o texto nos elementos?

A tarefa não foi tão difícil quanto parecia. Para resolvê-lo a partir do valor hexadecimal, precisamos obter o brilho do elemento. Fizemos isso com duas funções auxiliares. A primeira traduz hexadecimal para 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;
};

A segunda função do RGB obtém o brilho do plano de fundo e decide se a cor é escura ou clara:

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';
};

Você pode pensar que agora tudo está pronto para o próximo passo. Mas não, ainda queremos suporte para um tema sombrio pronto para uso? Sim! Nós queremos!

Você provavelmente notou que passamos uma bandeira para nossa função inverse. Vamos mudar um pouco o nosso código com este sinalizador em mente:

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);

  ...
}

Isso é tudo. Podemos dar uma lista de cores:

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(),
  ...
}

Em dois dias, com a ajuda do nosso designer, criei uma biblioteca que, na saída, fornece uma paleta de cores para um tema escuro e claro.

Próxima pergunta: como usá-lo?

Muito simples. Para implementar o esquema de cores gerado, usamos a inserção de variáveis ​​CSS através do bloco de estilos. Isso evita conflitos com variáveis ​​CSS usadas por outras bibliotecas 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);

E agora o mais delicioso. Atenção Atenção! Agora, com algumas linhas, quando adicionamos suporte a temas escuros para metade dos elementos:

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

O resultado é uma biblioteca na qual passamos a cor principal da marca e obtemos um conjunto de variáveis ​​CSS, que usamos para colorir nosso projeto.

Passava a maior parte do tempo escolhendo um esquema de cores. Eu tive que classificar manualmente vários parâmetros diferentes para que as cores fossem combinadas. Mas agora, a cada iteração da seleção de cores para as novas seções do portal, economizamos vários dias.

Como o designer participou da criação do algoritmo, ainda não havia nenhum caso de ele estar insatisfeito com as cores geradas pela biblioteca. Sim, e os esquemas de cores não são muito grandes, é difícil cometer erros.

Sublinho mais uma vez que não reivindicamos ser a única decisão correta. Essa ideia é implementada e funciona bem. Tentei apresentar os pontos principais e os detalhes e o escopo da implementação dependem apenas de você e seu projeto.

Obrigado pela atenção.

All Articles