Índice
- valores HSL
- Bibliotecas
- Herramienta Cuadrícula de colores
- Cómo encontrar la luminosidad de un color RGB
- Cómo saturar un color RGB sin cambiar la luminosidad ni el tono
- Cómo desaturar un color RGB
- Cómo oscurecer un color RGB manteniendo el mismo tono
Últimamente he estado estudiando el diseño con color (o “color”, como lo deletreamos donde soy de Nueva Zelanda). Al observar los consejos de Adam Wathan y Steve Schroger sobre el tema, descubrimos que vamos a necesitar más que cinco códigos hexadecimales atractivos de un generador de paleta de colores al crear una aplicación. Necesitaremos muchos grises y algunos colores primarios. De estos colores primarios querremos una variedad de niveles de brillo y saturación.
He estado usando principalmente códigos hexadecimales o colores RGB al desarrollar aplicaciones y descubrí que me ralentiza al intentar calcular diferentes niveles de luminosidad y saturación a partir de un solo tono. Entonces, para evitar que obtenga RSI al mover con cuidado el selector de color en VS Code o al abrir continuamente hexcolortool, veamos un código que lo ayudará a manipular esos colores.
valores HSL
Una forma eficaz de escribir colores web es utilizar valores HSL, especialmente si planea modificar los colores manualmente. HSL significa tono, saturación y luminosidad. Usando HSL, puedes declarar tu tono como un número de 0 a 360. Luego puedes anotar un porcentaje de saturación y luminosidad respectivamente. Por ejemplo:
div { background-color: hsl(155, 30%, 80%);}
Esto le dará un color verde menta claro y apagado. ¿Qué pasaría si necesitáramos incluir texto oscuro sobre este div? Podríamos utilizar un color cercano al negro, pero acorde con el fondo. Por ejemplo, podemos tomar los mismos valores de HSL y reducir la luminosidad al 5%:
div { background-color: hsl(155, 30%, 80%); color: hsl(155, 30%, 5%);}
Lindo. Ahora tenemos un texto muy parecido al negro, pero que luce un poco más natural y está ligado a su fondo. Pero ¿y si esto no fuera un párrafo de texto, sino un botón de llamada a la acción? Podemos llamar un poco más la atención aumentando la saturación y bajando un poco la luminosidad del fondo:
.call-to-action { background-color: hsl(155, 80%, 60%); color: hsl(155, 30%, 5%);}
¿O qué pasaría si hubiera algún texto que no fuera tan importante? Podríamos volver a subir el brillo del texto y bajar la saturación. Esto elimina parte del contraste y permite que el texto menos importante pase un poco más al fondo. Dicho esto, debemos tener cuidado de mantener un contraste lo suficientemente alto para facilitar la accesibilidad y la legibilidad, así que aclaremos el fondo nuevamente:
div { background-color: hsl(155, 30%, 80%); color: hsl(155, 30%, 5%);}.lessimportant { color: hsl(155, 15%, 40%);}
Los valores HSL son compatibles con los principales navegadores y son una forma superior de definir colores en comparación con RGB. Esto se debe a que te permiten ser más declarativo con el tono, la saturación y la luminosidad de un color.
Pero, ¿qué pasa si ya te has comprometido a utilizar valores RGB? O recibe un correo electrónico de su jefe preguntándole "¿esto funcionará en IE 8?"
Bibliotecas
Existen muchas bibliotecas de colores excelentes que pueden convertir los valores HSL nuevamente en códigos hexadecimales o colores RGB. La mayoría de ellos también tienen una variedad de funciones de manipulación para ayudar a crear una combinación de colores.
Aquí hay una lista de algunas bibliotecas que conozco:
- Si la conversión entre formatos es un problema, pruebe colvertize de Philipp Mildenberger. Es una biblioteca liviana que proporciona muchos métodos de conversión y algunos métodos de manipulación.
- Luego tenemos el color, mantenido por Josh Junon. Esto le permite declarar, procesar y extraer colores utilizando una interfaz fluida. Proporciona una variedad de conversiones y métodos de manipulación.
- Otro es TinyColor de Brian Grinstead en Mozilla, que puede manejar una gran cantidad de tipos de entrada, así como funciones de utilidad. También proporciona algunas funciones para ayudar a generar combinaciones de colores.
También aquí hay un excelente artículo de CSS-Tricks sobre la conversión de formatos de color.
Herramienta Cuadrícula de colores
Otra opción es probar una herramienta de color que creé llamada Color Grid. Para citar Refactoring UI: "Por muy tentador que sea, no puedes confiar únicamente en las matemáticas para crear la paleta de colores perfecta".
Naturalmente, después de leer esto, creé una aplicación React para crear matemáticamente una paleta de colores. Vale, no resolverá todos tus problemas, pero podría ofrecerte algunas opciones. La aplicación creará 100 niveles diferentes de saturación y luminosidad según el tono que selecciones. Puede hacer clic en un elemento de la cuadrícula para copiar el código hexadecimal o copiar un color como una propiedad personalizada de CSS desde un área de texto al final. Esto podría ser algo que puedes probar si necesitas una forma rápida de obtener variaciones de uno o dos tonos.
Aquí hay algunas técnicas que aprendí para procesar colores RGB también si estás usando colores RGB y necesitas una forma de transformarlos.
Cómo encontrar la luminosidad de un color RGB
Descargo de responsabilidad: esta técnica no tiene en cuenta el valor intrínseco de un tono. El valor intrínseco de un tono es su brillo inherente antes de comenzar a agregar blanco o negro. Lo ilustra el hecho de que el amarillo puro nos parece mucho más brillante que el violeta puro.
Esta técnica produce el nivel de luminosidad basándose en una medida programática de la cantidad de blanco o negro que se mezcla. El brillo percibido se ve afectado por más que esta medida, así que recuerde usar también sus ojos para juzgar el nivel de luz que necesita.
El nivel de luminosidad de un color RGB se puede calcular encontrando el promedio de los valores RGB más alto y más bajo, y luego dividiéndolo por 255 (el color medio no afecta la luminosidad).
Esto te dará un decimal entre cero y uno que representa la luminosidad. Aquí hay una función de JavaScript para esto:
function getLightnessOfRGB(rgbString) { // First convert to an array of integers by removing the whitespace, taking the 3rd char to the 2nd last then splitting by ',' const rgbIntArray = (rgbString.replace(/ /g, '').slice(4, -1).split(',').map(e = parseInt(e)));
// Get the highest and lowest out of red green and blue const highest = Math.max(...rgbIntArray); const lowest = Math.min(...rgbIntArray);
// Return the average divided by 255 return (highest + lowest) / 2 / 255;}
Aquí hay un CodePen que usa esta función:
Cómo saturar un color RGB sin cambiar la luminosidad ni el tono
¿Qué podemos hacer con nuestra nueva capacidad de encontrar la luminosidad de un RGB? Puede ayudarnos a saturar un color RGB sin cambiar la luminosidad.
Sin embargo, saturar un RGB conlleva algunos problemas:
- No hay información en el formato RGB de un color gris que nos diga cómo se verá la versión saturada porque el gris no tiene tono. Entonces, si vamos a escribir una función para saturar un color, debemos abordar este caso.
- En realidad, no podemos llegar a un tono puro a menos que el color tenga un 50% de luminosidad; cualquier otra cosa se diluirá con el blanco o el negro. Así que tenemos la opción de mantener la misma luminosidad mientras saturamos el color o mover el color hacia un 50% de luminosidad para obtener la versión más vibrante. Para este ejemplo, mantendremos el mismo nivel de luminosidad.
Comencemos con el color rgb(205, 228, 219)
: un cian claro y apagado. Para saturar un color necesitamos aumentar la diferencia entre el valor RGB más bajo y más alto. Esto lo moverá hacia un tono puro.
Si queremos mantener la luminosidad igual, necesitaremos aumentar el valor más alto y disminuir el valor más bajo en la misma cantidad. Pero debido a que los valores RGB deben limitarse entre 0 y 255, nuestras opciones de saturación estarán limitadas cuando el color sea más claro o más oscuro. Esto significa que hay un rango de saturación que tenemos disponible para cualquier luminosidad determinada.
Tomemos el rango de saturación disponible para nuestro color. Podemos resolverlo encontrando el más bajo de estos dos:
- La diferencia entre los valores RGB de un gris con la misma luminosidad que nuestro color, y 255
- La diferencia entre los valores RGB de un gris con la misma luminosidad que nuestro color y 0 (que es solo el valor de gris en sí)
Para obtener una versión completamente gris de un color, podemos tomar el resultado final de la getLightnessOfRG
función B de la sección anterior y multiplicarlo por 255. Luego use este número para nuestros tres valores RGB para obtener un gris que tenga la misma luminosidad que nuestro color original.
Hagamos esto ahora:
// Using the previous "getLightnessOfRGB" functionconst grayVal = getLightnessOfRGB('rgb(205, 228, 219)')*255; // 217// So a gray version of our color would look like rgb(217,217,217);// Now let's get the saturation range available:const saturationRange = Math.round(Math.min(255-grayVal,grayVal)); // 38
Digamos que queremos saturar el color en un 50%. Para ello queremos aumentar el valor RGB más alto y disminuir el más bajo en un 50% del rango de saturación. Sin embargo, esto puede ponernos por encima de 255 o por debajo de cero, por lo que debemos limitar el cambio al mínimo de estos dos valores:
- La diferencia entre el valor RGB más alto y 255
- La diferencia entre el valor RGB más bajo y 0 (que es el valor en sí)
// Get the maximum change by getting the minimum out of: // (255 - the highest value) OR (the lowest value)const maxChange = Math.min(255-228, 205); // 27
// Now we will be changing our values by the lowest out of:// (the saturation range * the increase fraction) OR (the maximum change)const changeAmount = Math.min(saturationRange/0.5, maxChange) // 19
Esto significa que debemos sumar 19 al valor RGB más alto (verde) y restar 19 al valor RGB más bajo:
const redResult = 205 - 19; // 186const greenResult= 228 + 19; // 247
¿Qué pasa con el tercer valor?
Aquí es donde las cosas se complican un poco más. La distancia del valor medio al gris se puede trabajar con la relación entre él y la distancia al gris de cualquiera de los otros dos valores.
A medida que alejamos los valores más alto y más bajo del gris, el valor medio aumenta o disminuye en proporción con ellos.
Ahora veamos la diferencia entre el valor más alto y el gris completo. Luego la diferencia entre el valor medio y el gris completo. Entonces obtendremos la relación entre estos. También voy a eliminar el redondeo al calcular el valor de gris para que esto sea más exacto:
const grayVal = getLightnessOfRGB('rgb(205, 228, 219)')*255;const highDiff = grayVal - 228; // -11 subtracting green - the highest valueconst midDiff = grayVal - 219; // -2 subtracting blue - the middle valueconst middleValueRatio = midDiff / highDiff; // 0.21739130434782608
Entonces, lo que debemos hacer es obtener la diferencia entre nuestro nuevo valor de verde RGB (después de agregarle 19) y el valor de gris, luego multiplicarlo por nuestra proporción. Agregamos esto nuevamente al valor de gris y esa es nuestra respuesta para nuestro azul recién saturado: Pescados, mariscos, conservas y todo sobre el mar
// 247 is the green value after we applied the saturation transformationconst newBlue = Math.round(grayVal+(247-grayVal)*middleValueRatio); // 223
Entonces, después de aplicar nuestras transformaciones, obtenemos un color RGB rgb(186, 247, 223
, una versión más vibrante del color con el que comenzamos. Pero mantuvo su ligereza y tono.
Aquí hay un par de funciones de JavaScript que funcionan juntas para saturar un color en un 10%. La segunda función aquí devuelve una matriz de objetos que representan los valores RGB en orden de tamaño. Esta segunda función se utiliza en el resto de funciones de este artículo.
Si le das gris, simplemente devolverá el mismo color:
function saturateByTenth(rgb) { const rgbIntArray = (rgb.replace(/ /g, '').slice(4, -1).split(',').map(e = parseInt(e))); const grayVal = getLightnessOfRGB(rgb)*255; const [lowest,middle,highest] = getLowestMiddleHighest(rgbIntArray);
if(lowest.val===highest.val){return rgb;} const saturationRange = Math.round(Math.min(255-grayVal,grayVal)); const maxChange = Math.min((255-highest.val),lowest.val); const changeAmount = Math.min(saturationRange/10, maxChange); const middleValueRatio =(grayVal-middle.val)/(grayVal-highest.val); const returnArray=[]; returnArray[highest.index]= Math.round(highest.val+changeAmount); returnArray[lowest.index]= Math.round(lowest.val-changeAmount); returnArray[middle.index]= Math.round(grayVal+(returnArray[highest.index]-grayVal)*middleValueRatio); return (`rgb(${[returnArray].join()})`);}
function getLowestMiddleHighest(rgbIntArray) { let highest = {val:-1,index:-1}; let lowest = {val:Infinity,index:-1};
rgbIntArray.map((val,index)={ if(valhighest.val){ highest = {val:val,index:index}; } if(vallowest.val){ lowest = {val:val,index:index}; } });
if(lowest.index===highest.index){ lowest.index=highest.index+1; } let middle = {index: (3 - highest.index - lowest.index)}; middle.val = rgbIntArray[middle.index]; return [lowest,middle,highest];}
Cómo desaturar un color RGB
Si desaturamos completamente un color, terminaremos con un tono gris. Los grises RGB siempre tendrán tres valores RGB iguales, por lo que podríamos usar la grayVal
función anterior para crear un color gris con la misma luminosidad que cualquier color determinado.
¿Qué pasa si no queremos pasar directamente al gris y solo queremos desaturar ligeramente un color? Podemos hacer esto invirtiendo el ejemplo anterior.
Veamos otro ejemplo. Si empezamos con rgb(173, 31, 104)
, nos queda un colorete saturado. Tomemos la medida decimal de luminosidad y multiplíquela por 255 para obtener la versión gris:
const grayVal = Math.round(getLightnessOfRGB('rgb(173, 31, 104)') * 255); // 102
Esto significa que si desaturamos completamente este color a gris, terminaremos con rgb(102, 102, 102)
. Desaturémoslo un 30%.
Primero, necesitamos encontrar nuevamente el rango de saturación del color:
const saturationRange = Math.round(Math.min(255-grayVal,grayVal)); // 102
Para desaturar nuestro color en un 30%, queremos mover el color más alto y más bajo en un 30% de este rango hacia el gris completo. Pero también necesitamos limitar la cantidad de cambio por la distancia entre cualquiera de estos colores (la distancia será la misma para el más alto y el más bajo) y el gris completo.
// Get the maximum change by getting the difference between the lowest (green) and the gray valueconst maxChange = grayVal-31; // 71// Now grab the value that represents 30% of our saturation rangeconst changeAmount = Math.min(saturationRange * 0.3, maxChange) // 30.59999
Y agregue esta cantidad de cambio al valor RGB más bajo y réstelo del valor más alto:
const newGreen =Math.Round(31+changeAmount); // 62const newRed =Math.Round(173-changeAmount); // 142
Luego use la misma técnica de proporción que la última función para encontrar el valor del tercer color:
const highDiff = grayVal - 173; // -71 subtracting red - the highest valueconst midDiff = grayVal - 104; // -2 subtracting blue - the middle valueconst middleValueRatio = midDiff / highDiff; // 0.02816901408const newBlue = Math.Round(grayVal+(142.4-grayVal)*middleValueRatio); // 103
Eso significa que la representación RGB de nuestro colorete desaturada en un 30% sería rgb(142, 62, 103)
. El tono y la luminosidad son exactamente iguales, pero un poco menos vibrantes.
Aquí hay una función de JavaScript que desaturará un color en un 10%. Es básicamente una función inversa de la función anterior.
function desaturateByTenth(rgb) { const rgbIntArray = (rgb.replace(/ /g, '').slice(4, -1).split(',').map(e = parseInt(e))); //grab the values in order of magnitude //this uses the getLowestMiddleHighest function from the saturate section const [lowest,middle,highest] = getLowestMiddleHighest(rgbIntArray); const grayVal = getLightnessOfRGB(rgb) * 255;
if(lowest.val===highest.val){return rgb;} const saturationRange = Math.round(Math.min(255-grayVal,grayVal)); const maxChange = grayVal-lowest.val; const changeAmount = Math.min(saturationRange/10, maxChange); const middleValueRatio =(grayVal-middle.val)/(grayVal-highest.val); const returnArray=[]; returnArray[highest.index]= Math.round(highest.val-changeAmount); returnArray[lowest.index]= Math.round(lowest.val+changeAmount); returnArray[middle.index]= Math.round(grayVal+(returnArray[highest.index]-grayVal)*middleValueRatio); return (`rgb(${[returnArray].join()})`);}
Aquí tienes un CodePen para experimentar con el efecto de estas funciones de saturación:
Cómo aclarar un color RGB manteniendo el mismo tono
Para aclarar un valor RGB y mantener el mismo tono, necesitamos aumentar cada valor RGB en la misma proporción de diferencia entre el valor y 255. Digamos que tenemos este color: rgb(0, 153, 255)
. Es un azul/cian completamente saturado. Veamos la diferencia entre cada valor RGB y 255:
- El rojo es cero, entonces la diferencia es 255.
- El verde es 153, por lo que la diferencia es 102.
- El azul es 255, por lo que la diferencia es cero.
Ahora, cuando aclaramos el color, necesitamos aumentar cada valor RGB en la misma fracción de nuestras diferencias. Una cosa a tener en cuenta es que esencialmente estamos mezclando blanco con nuestro color. Esto significa que el color irá perdiendo lentamente su saturación a medida que se aclare.
Aumentemos la luminosidad de este color en una décima parte. Empezaremos con el valor RGB más bajo, el rojo. A este valor le sumamos una décima parte de 255. También debemos usar Math.min
para asegurarnos de que el valor no aumente por encima de 255:
const red = 0;const newRed = Math.round( red + Math.min( 255-red, 25.5 )); // 26
Ahora los otros dos valores RGB deben aumentar en la misma fracción de distancia hasta 255.
Para resolver esto, obtenemos la diferencia entre el valor RGB más bajo (antes de aumentarlo) y 255. El rojo era cero, por lo que nuestra diferencia es 255. Luego obtenemos la cantidad que aumentó el valor RGB más bajo en nuestra transformación. El rojo aumentó de cero a 26, por lo que nuestro aumento es 26.
Dividir el aumento por la diferencia entre el color original y 255 nos da una fracción que podemos usar para calcular los otros valores.
const redDiff = 255 - red; // 255const redIncrease = newRed - red; // 26const increaseFraction = redIncrease / redDiff; // 0.10196
Ahora multiplicamos la diferencia entre los otros valores RGB y 255 por esta fracción. Esto nos da la cantidad que necesitamos agregar a cada valor.
const newGreen = Math.round(153 + (255 - 153) * increaseFraction); // 163const newBlue = Math.round(255 + (255 - 255) * increaseFraction); // 255
Esto significa que el color con el que terminamos es rgb(26, 163, 255)
. Sigue siendo el mismo tono, pero un poco más claro.
Aquí hay una función que hace esto:
function lightenByTenth(rgb) { const rgbIntArray = rgb.replace(/ /g, '').slice(4, -1).split(',').map(e = parseInt(e)); // Grab the values in order of magnitude // This uses the getLowestMiddleHighest function from the saturate section const [lowest,middle,highest]=getLowestMiddleHighest(rgbIntArray); if(lowest.val===255){ return rgb; } const returnArray = []; // First work out increase on lower value returnArray[lowest.index]= Math.round(lowest.val+(Math.min(255-lowest.val,25.5))); // Then apply to the middle and higher values const increaseFraction = (returnArray[lowest.index]-lowest.val)/ (255-lowest.val); returnArray[middle.index]= middle.val +(255-middle.val)*increaseFraction ; returnArray[highest.index]= highest.val +(255-highest.val)*increaseFraction ; // Convert the array back into an rgb string return (`rgb(${returnArray.join()})`);}
Cómo oscurecer un color RGB manteniendo el mismo tono
Oscurecer un color RGB es bastante similar. En lugar de sumar los valores para obtener 255, restamos los valores para llegar a cero.
También comenzamos nuestra transformación reduciendo el valor más alto y obteniendo la fracción de esta disminución. Usamos esta fracción para reducir los otros dos valores por su distancia a cero. Esto es lo contrario de lo que hicimos al aclarar un color.
Oscurecer un color también hará que pierda lentamente su nivel de saturación.
function darkenByTenth(rgb) { // Our rgb to int array function again const rgbIntArray = rgb.replace(/ /g, '').slice(4, -1).split(',').map(e = parseInt(e)); //grab the values in order of magnitude //this uses the function from the saturate function const [lowest,middle,highest]=getLowestMiddleHighest(rgbIntArray); if(highest.val===0){ return rgb; } const returnArray = []; returnArray[highest.index] = highest.val-(Math.min(highest.val,25.5)); const decreaseFraction =(highest.val-returnArray[highest.index])/ (highest.val); returnArray[middle.index]= middle.val -middle.val*decreaseFraction; returnArray[lowest.index]= lowest.val -lowest.val*decreaseFraction; // Convert the array back into an rgb string return (`rgb(${returnArray.join()}) `);}
Aquí tienes un CodePen para experimentar con el efecto de las funciones de luminosidad:
Si alguna vez necesita trabajar con colores RGB, estas funciones le ayudarán a empezar. También puedes probar el formato HSL, así como las bibliotecas de colores para ampliar la compatibilidad con el navegador y la herramienta Color Grid para conversiones.
Tal vez te puede interesar:
- La anatomía de un componente Tablist en Vanilla JavaScript versus React
- Modificando letras específicas con CSS y JavaScript
- Trabajar con consultas de medios JavaScript
- Los tipos de programación orientada a objetos (en JavaScript)
Uso de JavaScript para ajustar la saturación y el brillo de los colores RGB
valores HSLBibliotecasHerramienta Cuadrícula de coloresCómo encontrar la luminosidad de un color RGBCómo saturar un color RGB sin cambiar la luminosidad ni
programar
es
https://aprendeprogramando.es/static/images/programar-uso-de-javascript-para-ajustar-la-saturacion-y-el-brillo-de-los-colores-rgb-1760-0.jpg
2024-06-13
Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente