Esquema de color sin la ayuda de un diseñador.


Seguramente muchos de ustedes han estado en una situación en la que necesitan elegir rápidamente los colores para la decoración, y el diseñador está ocupado con tareas más importantes, de mal humor o de vacaciones. La tarea no es difícil, pero a veces hay que esperar una respuesta durante varios días.

Mi nombre es Emil Frolov, soy un techlide en el equipo de servicios internos de DomKlik. En este artículo, te contaré cómo nació la idea de una biblioteca, que ahora ahorra mucho tiempo al elegir los colores. La solución es simple, pero muy útil, póngala en servicio.

Especialmente si necesita elegir colores para el esquema oscuro.

Tarea


DomKlik tiene un portal corporativo, cada sección del cual tiene su propio esquema de color. Anteriormente, para crear una nueva sección, cada vez que tenía que atormentar a los diseñadores y pedirles que eligieran un nuevo conjunto de colores y los transfirieran a la interfaz. Resultó una gran cantidad de código extra, pasó mucho tiempo en correspondencia, espera y coordinación. Tenía muchas ganas de simplificar y acelerar todo el proceso.

Buscamos soluciones preparadas en Internet, pero no encontramos nada adecuado. Y luego decidieron escribir una biblioteca: ingresa el color (marca) que le da el diseñador, y la biblioteca selecciona algunos colores más adecuados. También queríamos que la biblioteca generara esquemas de color oscuro también.
Esta no es una receta para la felicidad, sino una idea que todos pueden desarrollar en el marco de su proyecto. Puedes ver una pequeña demostración aquí .

Idea y solucion


Pensamos cómo hacerlo. Comenzamos con un algoritmo básico de generación de color. En estas Internet tuyas nuevamente no se encontró nada listo. Pero encontraron una biblioteca que puede cambiar diferentes configuraciones de color.

Mucha gente sabe que hay muchos algoritmos de coincidencia de colores diferentes:



no veo ningún sentido en pintarlos, ya lo han hecho cientos de veces antes que yo. Pero hay algunos puntos clave:

  1. Para nosotros son redundantes.
  2. Quería elegir colores para mí.

Por lo tanto, el diseñador y desarrollador, fusionado en un solo impulso, decidió retomar el esquema manualmente una vez.

Para empezar, describimos los colores básicos:

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

En base a esto, puede comenzar a crear. Obtenemos objetos para trabajar con colores básicos.

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

Creo que no tiene sentido describir completamente la selección completa de colores, pero, por ejemplo, daré un par de líneas:

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

Después de terminar de elegir los colores primarios, nos enfrentamos al siguiente problema.

¿Y qué color muestra el texto en los elementos?

La tarea no fue tan difícil como parecía. Para resolverlo a partir del valor hexadecimal, necesitamos obtener el brillo del elemento. Lo hicimos con dos funciones auxiliares. El primero traduce hexadecimal a 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;
};

La segunda función de RGB obtiene el brillo del fondo y decide si el color es oscuro o claro:

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

Puede pensar que ahora todo está listo para el siguiente paso. Pero no, ¿aún queremos soporte para un tema oscuro fuera de la caja? ¡Si! ¡Lo queremos!

Probablemente hayas notado que pasamos una bandera a nuestra función inverse. Cambiemos un poco nuestro código con esta bandera en 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);

  ...
}

Eso es todo. Podemos dar una lista de colores:

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

En dos días, con la ayuda de nuestro diseñador, creé una biblioteca, que en la salida da una paleta de colores para un tema oscuro y claro.

Siguiente pregunta: ¿cómo usarlo?

Muy simple. Para implementar el esquema de color generado, utilizamos la inserción de variables CSS a través del bloque de estilo. Esto evita conflictos con las variables CSS que usan otras 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);

Y ahora lo más delicioso. ¡Atención Atención! Ahora, con unas pocas líneas, cuando agregamos compatibilidad con temas oscuros para la mitad de los elementos:

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

El resultado es una biblioteca en la que pasamos el color principal de la marca y obtenemos un conjunto de variables CSS, que luego usamos para colorear nuestro proyecto.

La mayor parte del tiempo se dedicó a elegir un esquema de color. Tuve que clasificar manualmente a través de un montón de parámetros diferentes para que los colores se combinaran entre sí. Pero ahora, en cada iteración de la selección de colores para las nuevas secciones del portal, ahorramos varios días.

Dado que el diseñador participó en la creación del algoritmo, todavía no había caso de que no estuviera satisfecho con los colores generados por la biblioteca. Sí, y los esquemas de color no son demasiado grandes, es difícil cometer errores.

Insisto una vez más en que no pretendemos ser la única decisión correcta. Esta idea se implementa y funciona bien. Traté de presentarle los puntos principales, y los detalles y el alcance de la implementación dependen solo de usted y su proyecto.

Gracias por la atención.

All Articles