Cómo configurar esquemas de color de aplicaciones con propiedades personalizadas de CSS
Publicado: 2022-03-10Las variables son una herramienta básica que ayuda a organizar los colores en un proyecto. Durante mucho tiempo, los ingenieros de front-end utilizaron variables de preprocesador para configurar colores en un proyecto. Pero ahora, muchos desarrolladores prefieren el mecanismo nativo moderno para organizar las variables de color: las propiedades personalizadas de CSS. Su ventaja más importante sobre las variables del preprocesador es que trabajan en tiempo real, no en la etapa de compilación del proyecto, y tienen soporte para el modelo en cascada que le permite usar la herencia y la redefinición de valores sobre la marcha.
Cuando intenta organizar un esquema de color de la aplicación, siempre puede colocar todas las propiedades personalizadas relacionadas con el color en la sección raíz, nombrarlas y usarlas en todos los lugares necesarios.
Consulte el Pen [Propiedades personalizadas para colores] (https://codepen.io/smashingmag/pen/RwaNqxW) de Artur Basak.
Esa es una opción, pero ¿lo ayuda a resolver problemas de tematización de aplicaciones, etiquetado en blanco, actualización de marca u organización de un modo claro u oscuro? ¿Qué sucede si necesita ajustar el esquema de color para aumentar el contraste? Con el enfoque actual, deberá actualizar cada valor en sus variables.
En este artículo, quiero sugerir un enfoque más flexible y resistente sobre cómo dividir variables de color usando propiedades personalizadas, que puede resolver muchos de estos problemas.
Configurar paleta de colores
La coloración de cualquier sitio web comienza con la configuración de un esquema de color. Tal esquema se basa en la rueda de colores. Por lo general, solo unos pocos colores primarios forman la base de una paleta, el resto son colores derivados: tonos y tonos medios. La mayoría de las veces, la paleta es estática y no cambia mientras se ejecuta la aplicación web.
De acuerdo con la teoría del color, solo hay unas pocas opciones para los esquemas de color:
- Esquema monocromático (un color primario)
- Esquema complementario (dos colores primarios)
- Esquema de tríada (tres colores primarios)
- Esquema tetradico (cuatro colores primarios)
- Patrón adyacente (dos o tres colores primarios)
Para mi ejemplo, generaré un esquema de color de tríada utilizando el servicio Paletton:

Ahora tengo tres colores principales. En base a estos, calcularé los tonos y medios tonos (el formato HSL en combinación con la función calc
es una herramienta muy útil para esto). Al cambiar el valor de luminosidad, puedo generar varios colores adicionales para la paleta.
Vea el Pen [Paleta HSL] (https://codepen.io/smashingmag/pen/OJNPaQW) de Artur Basak.
Ahora bien, si se modifica la paleta, será necesario cambiar solo el valor de los colores primarios. El resto se recalculará automáticamente.
Si prefieres los formatos HEX o RGB, entonces no importa; se puede formar una paleta en la etapa de compilación del proyecto con las funciones correspondientes del preprocesador (por ejemplo, con SCSS y la función color-adjust
). Como mencioné antes, esta capa es mayormente estática; es extremadamente raro que la paleta se pueda cambiar en una aplicación en ejecución. Por eso podemos calcularlo con preprocesadores.
Nota : Recomiendo también generar tanto HEX literal como RGB para cada color. Esto permitirá jugar con el canal alfa en el futuro.
Vea el Pen [SCSS Palette](https://codepen.io/smashingmag/pen/oNxgQqv) de Artur Basak.
El nivel de la paleta es el único nivel en el que el color está codificado directamente en los nombres de las variables, es decir, podemos identificar el color de forma única leyendo el nombre.
Definir colores temáticos o funcionales
Una vez hecha la paleta, el siguiente paso es el nivel de colores funcionales . En este nivel, el valor del color no es tan importante como su propósito, la función que realiza y lo que colorea exactamente. Por ejemplo, el color principal o de la marca de la aplicación, el color del borde, el color del texto sobre un fondo oscuro, el color del texto sobre un fondo claro, el color de fondo del botón, el color del enlace, el color del enlace flotante, el color del texto de la sugerencia, etc. .
Estas son cosas extremadamente comunes para casi cualquier sitio web o aplicación. Podemos decir que tales colores son responsables de cierto tema de color de la aplicación. Además, los valores de dichas variables se toman estrictamente de la paleta. Por lo tanto, podemos cambiar fácilmente los temas de la aplicación simplemente operando con diferentes paletas de colores.
A continuación, he creado tres controles de interfaz de usuario típicos: un botón, un enlace y un campo de entrada. Están coloreados usando variables funcionales que contienen valores de la paleta que generé previamente arriba. La principal variable funcional responsable del tema de la aplicación (marca condicional) es la variable de color primario.
Usando los tres botones en la parte superior, puede cambiar de tema (cambiar el color de la marca para los controles). El cambio se produce mediante el uso de la API de CSSOM adecuada (setProperty).
Vea el bolígrafo [Colores funcionales] (https://codepen.io/smashingmag/pen/poyvQLL) de Artur Basak.
Este enfoque es conveniente no solo para crear temas, sino también para configurar páginas web individuales. Por ejemplo, en el sitio web zubry.by, utilicé una hoja de estilo común y una variable funcional --page-color
para colorear el logotipo, los encabezados, los controles y la selección de texto para todas las páginas. Y en los estilos propios de cada página, acabo de redefinir esta variable para configurar la página con su color primario individual.

Usar colores de componentes
Los proyectos web grandes siempre contienen descomposición; dividimos todo en pequeños componentes y los reutilizamos en muchos lugares. Cada componente generalmente tiene su propio estilo, lo que significa que no importa lo que usamos para descomponer los módulos BEM o CSS, u otro enfoque; es importante que cada fragmento de código se pueda denominar alcance local y reutilizarse.
En general, veo el sentido de usar variables de color a nivel de componente en dos casos.
La primera es cuando los componentes que de acuerdo con la guía de estilo de la aplicación se repiten con diferentes configuraciones, por ejemplo, botones para diferentes necesidades como botón principal (marca), botón secundario, terciario, etc.

El segundo es cuando los componentes que tienen varios estados con diferentes colores, por ejemplo, estados de botón, activo y de enfoque; estados normales e inválidos para el campo de entrada o selección, y así sucesivamente.
Un caso más raro en el que las variables de componentes pueden ser útiles es la funcionalidad de una "etiqueta blanca". La "etiqueta blanca" es una característica del servicio que permite al usuario personalizar o marcar alguna parte de la interfaz de usuario para mejorar la experiencia de interacción con sus clientes. Por ejemplo, documentos electrónicos que un usuario comparte con sus clientes a través de un servicio o plantillas de correo electrónico. En este caso, las variables a nivel de componente ayudarán a configurar ciertos componentes por separado del resto del tema de color de la aplicación.
En el siguiente ejemplo, ahora he agregado controles para personalizar los colores del botón principal (marca). Usando variables de color del nivel del componente, podemos configurar los controles de la interfaz de usuario por separado.
Consulte el Pen [Colores de componentes] (https://codepen.io/smashingmag/pen/LYNEXdw) de Artur Basak.

¿Cómo determinar qué nivel tiene una variable?
Me encontré con la cuestión de cómo entender qué se puede poner en la raíz (tema o nivel funcional) y qué dejar en el nivel de un componente. Esta es una excelente pregunta que es difícil de responder sin ver la situación en la que está trabajando.
Desafortunadamente, el mismo enfoque que en la programación no funciona con colores y estilos, si vemos tres piezas de código idénticas, entonces necesitamos refactorizarlas.
El color se puede repetir de un componente a otro, pero esto no significa que sea una regla. No puede haber relación entre tales componentes. Por ejemplo, el borde del campo de entrada y el fondo del botón principal. Sí, en mi ejemplo anterior ese es el caso, pero veamos el siguiente ejemplo:
Vea el Pen [División de colores: solo paleta] (https://codepen.io/smashingmag/pen/YzqPRLX) de Artur Basak.
El color gris oscuro se repite: este es el borde del campo de entrada, el color de relleno del icono de cierre y el fondo del botón secundario. Pero estos componentes no están de ninguna manera conectados entre sí. Si cambia el color del borde del campo de entrada, no cambiaremos el fondo del botón secundario. Para tal caso, debemos mantener aquí solo la variable de la paleta.

¿Qué pasa con el verde? Podemos definirlo claramente como el color principal o de la marca, lo más probable es que si cambia el color del botón principal, entonces también cambie el color del enlace y encabezado del primer nivel.
¿Qué pasa con el rojo? El estado no válido de los campos de entrada, los mensajes de error y los botones destructivos tendrán el mismo color en todo el nivel de la aplicación. Este es un patrón. Ahora puedo definir varias variables funcionales comunes en la sección raíz:
Vea el bolígrafo [división de colores: nivel funcional] (https://codepen.io/smashingmag/pen/MWyYzGX) de Artur Basak.
En cuanto al nivel de colores de los componentes, podemos identificar fácilmente los componentes que se pueden personalizar mediante propiedades personalizadas.
El botón se repite con diferentes configuraciones, el color de fondo y el texto para diferentes casos de uso cambian: caso primario, secundario, terciario, destructivo o negativo.
El campo de entrada tiene dos estados: incorrecto y normal, donde los colores de fondo y borde difieren. Entonces, pongamos estas configuraciones en variables de color al nivel de los componentes correspondientes.
Para el resto de componentes no es necesario definir variables locales de color, esto será redundante.
Vea el bolígrafo [división de colores: nivel de componente] (https://codepen.io/smashingmag/pen/BaKyGVR) de Artur Basak.
Debe sumergirse en el lenguaje de patrones de su proyecto, que probablemente esté siendo desarrollado por el equipo de diseño y UX. Los ingenieros debemos comprender a fondo todo el concepto de un lenguaje visual, solo así podremos determinar qué es común y debe vivir a nivel funcional, y qué debe permanecer en el ámbito local de visibilidad.
Pero no todo es tan complicado, hay cosas obvias. El fondo general de la página, el fondo y el color del texto principal, en la mayoría de los casos esto es lo que marca el tema de tu aplicación. Es extremadamente conveniente recopilar las cosas que son responsables de la configuración de un modo particular (como el modo oscuro o claro).
¿Por qué no poner todo en la sección raíz?
Tuve tal experiencia. En el proyecto Lition, el equipo y yo nos enfrentamos al hecho de que necesitábamos admitir IE11 para la aplicación web, pero no para el sitio web y los aterrizajes. Se utilizó un UI Kit común entre los proyectos, y decidimos poner todas las variables en la raíz, esto nos permitirá redefinirlas en cualquier nivel.
Y también con este enfoque para la aplicación web y el caso de IE11, simplemente pasamos el código a través del siguiente complemento de posprocesador y transformamos estas variables en literales para todos los componentes de la interfaz de usuario en el proyecto. Este truco solo es posible si todas las variables se definieron en la sección raíz porque el posprocesador no puede comprender los detalles del modelo en cascada.

Ahora entiendo que ese no era el camino correcto. En primer lugar, si coloca los colores de los componentes en la sección raíz, rompe el principio de separación de preocupaciones. Como resultado, puede terminar con CSS redundante en la hoja de estilos. Por ejemplo, tienes la carpeta de componentes donde cada componente tiene sus propios estilos. También tiene una hoja de estilo común donde describe las variables de color en la sección raíz. Decide eliminar el componente del botón; en este caso, debe recordar eliminar también las variables asociadas con el botón del archivo de estilos comunes.
En segundo lugar, esta no es la mejor solución en términos de rendimiento. Sí, un cambio de color provoca solo el proceso de volver a pintar, no el rediseño/diseño, esto en sí mismo no es demasiado costoso, pero cuando realiza algunos cambios en el nivel más alto, utilizará más recursos para verificar todo el árbol que cuando estos los cambios están en un área local pequeña. Recomiendo leer el benchmark de rendimiento de las variables CSS de Lisi Linhart para más detalles.
En mi proyecto actual Tispr, el equipo y yo usamos split y no volcamos todo en la raíz, en el nivel alto solo una paleta y colores funcionales. Además, no le tenemos miedo a IE11, porque este problema lo resuelve el polyfill correspondiente. Simplemente instale el módulo npm ie11-custom-properties e importe la biblioteca en el paquete JS de su aplicación:
// Use ES6 syntax import "ie11-custom-properties"; // or CommonJS require('ie11-custom-properties');
O agregue el módulo por etiqueta de secuencia de comandos:
<script async src="./node_modules/ie11-custom-properties/ie11CustomProperties.js">
Además, puede agregar la biblioteca sin npm a través de CDN. El trabajo de este polyfill se basa en el hecho de que IE11 tiene un soporte mínimo para las propiedades personalizadas, donde las propiedades se pueden definir y leer en función de la cascada. Esto no es posible con propiedades que comienzan con guiones dobles, pero posiblemente con un solo guión (el mecanismo similar a los prefijos de proveedores). Puede leer más sobre esto en la documentación del repositorio, así como familiarizarse con algunos límites. Otros navegadores ignorarán este polyfill.
A continuación se muestra una paleta de la aplicación web Tispr, así como los controles de la funcionalidad de "etiqueta blanca" para los documentos electrónicos (como contratos de usuario, facturas o propuestas).


¿Por qué no almacenar variables de color en el lado de JavaScript?
Otra pregunta razonable: ¿por qué no almacenar la paleta y las variables de función en código JavaScript? Esto también se puede cambiar dinámicamente y luego redefinir los colores a través de estilos en línea. Esta podría ser una opción, pero lo más probable es que este enfoque sea menos óptimo ya que necesita tener acceso a ciertos elementos y cambiar sus propiedades de color. Con las variables CSS, solo cambiará una sola propiedad, es decir, el valor de la variable.
En JavaScript, no hay funciones nativas o API para trabajar con colores. En el Módulo 5 de color CSS, habrá muchas oportunidades para hacer colores derivados o calcularlos de alguna manera. Desde la perspectiva del futuro, las propiedades personalizadas de CSS son más ricas y flexibles que las variables de JS. Además, con las variables JS, no habrá posibilidad de usar la herencia en cascada y esa es la principal desventaja.
Conclusión
Dividir los colores en tres niveles (paleta, funcional y componente) puede ayudarlo a adaptarse mejor a los cambios y nuevos requisitos mientras trabaja en un proyecto. Creo que las propiedades personalizadas de CSS son la herramienta adecuada para organizar la división de colores; no importa lo que use para diseñar: CSS puro, preprocesadores o enfoque de CSS en JS.
Llegué a este enfoque a través de mi propia experiencia, pero no estoy solo. Sara Soueidan describió en su artículo un enfoque similar en el que dividió las variables en niveles globales y de componentes.
También me gustaría sugerir leer el artículo de Lea Verou donde describe posibles casos de aplicación de variables CSS (no solo en términos de color).