Olá Web Developer. Hoje vou mostrar como ordenar elementos por cores usando JavaScript. Isso pode ser útil caso você tenha algo como uma galeria de fotos. Além disso também vamos acabar aprendendo como fazer conversão de cores entre os modelos RGB
e Hexadecimal
.
Eu usei quando fui criar uma imagem para o Instagram mostrando os cursos da TreinaWeb. Criar um código para ordenar os elementos do site e tirar print da tela foi bem mais rápido do que fazer manualmente em um editor de imagem, e teve um resultado melhor do que quando tentei ordenar os elementos do HTML manualmente também.
Como definir a ordem das cores?
O modo mais comum de se ordenar cores é usando o Círculo Cromático
, mostrado na imagem abaixo:
Eu já falei sobre ele e sobre como combinar cores aqui no blog. Não se esqueça de dar uma conferida!
É muito comum em programação utilizarmos os modelos RGB
ou Hexadecimal
para declarar cores, porém, o que vem depois de rgb(32, 15, 59)
?.
Formação Desenvolvedor Front-end
Conhecer a formaçãoTambém temos o modelo HSL
(Hue - Matiz/Tonalidade, Saturation - Saturação, Lightness - Brilho). As cores (vermelho, verde, azul, etc) são definidas pela matiz, a qual é indicada por um ângulo no círculo. Começamos no topo, 0º, que indica o vermelho, e podemos ir mudando de cores conforme vamos indo aos 360º. Isso é bem melhor para usarmos na ordenação, depois de 121 vem 122, simples assim.
Então a primeira coisa que vamos fazer é converter nossas cores para o modelo HSL
.
Convertendo Cores para HSL
É mais simples fazer a conversão para HSL
a partir do modelo RGB
, que possui números de 0 a 255. Se você estiver com cores em Hexadecimal
, que utiliza valores entre 00 e FF, basta converter para RGB
primeiro.
Hexadecimal para RGB
Os valores entre 00 e FF são basicamente 0 a 255 em hexadecimal. Isso é fácil de converter. Vamos criar uma função que vai pegar cada par de cores do código hexadecimal e retornar como números na base decimal. Então um FF deve retornar 255.
// exemplo de cor: #15FA3D
function hexToRGB(color){
color = color.replace('#', ''); // vamos remover o #
// e pegar os valores de Red, Green e Blue
let red = color.substr(0, 2),
green = color.substr(2, 2),
blue = color.substr(4, 2);
// agora vamos converter a string em número com o parseInt
// por estar em hexadecimal, indicamos a base 16
red = parseInt(red, 16);
green = parseInt(green, 16);
blue = parseInt(blue, 16);
// e vamos retornar como um array
return [red, green, blue];
}
// saída esperada: [21, 250, 61]
Formatando cores RGB
Já temos nossa cor hexadecimal em RGB em um formato de Array, o que nos facilita na hora de pegar cada uma das cores. Mas e se inicialmente já tivermos uma cor em RGB? Vamos criar uma função para formatar cores RGB para o formato que estamos usando.
É comum tanto o uso do RGB quanto o RGBA, então vamos primeiro deixar apenas os números, separar pelas vírgulas e pegar os valores de Red, Green e Blue.
// exemplo de cor: rgba(25, 15, 200, 0.8)
function formatRGB(color){
// removemos as letras e parênteses
color = color.replace(/[rgba()]/gi, '');
// separamos por vírgulas
color = color.split(',');
// agora teríamos algo como ["25", " 15", " 200", " 0.8"]
// vamos pegar cada um dos valores das strings e converter para números
const red = parseInt(color[0]),
green = parseInt(color[1]),
blue = parseInt(color[2]);
return [red, green, blue];
}
// saída esperada: [25, 15, 200]
Convertendo RGB para HSL
Para chegarmos na parte de ordenação precisamos das cores em HSL
. Essa parte é um pouco mais complexa, então eu vou montar a função aos poucos para ir explicando melhor cada pedaço, e no final eu mostro a função inteira. Para não ficar repetindo, as partes já explicadas serão substituídas por ...
.
Vamos começar simplesmente declarando a função, que vai receber separadamente os valores de Red, Green e Blue.
function RGBToHSL(r, g, b){
}
Os valores de R, G e B sempre serão um número entre 0 e 255. Primeiro temos que transformar esses números em um valor entre 0 e 1. Para isso, basta dividí-los por 255.
function RGBToHSL(r, g, b){
r /= 255;
g /= 255;
b /= 255;
// lembrando que
// r/= 255 é igual a
// r = r / 255;
}
Agora vamos pegar qual o maior e o menor valor entre esses três números. Para isso utilizamos Math.min
e Math.max
.
Também vamos declarar uma variável chamada delta
, que vai indicar a diferença entre o maior e o menor valor, e por último já vamos declarar as variáveis h
, s
e l
, que terão os valores para termos as cores no modelo HSL
.
function RGBToHSL(r, g, b){
...
let min = Math.min(r, g, b),
max = Math.max(r, g, b),
delta = max - min,
h = 0,
s = 0,
l = 0;
}
Cálculo da Matiz
Agora podemos começar a calcular cada uma das propriedades. Primeiro vamos calcular Hue
(matiz). Temos algumas regrinhas para isso:
- Se todos os valores (r, g e b) são iguais, h deve ser 0.
- Se a maior cor for
Red
, a fórmula deve ser ((g - b) / delta) % 6 - Se a maior cor for
Green
, a fórmula deve ser (b - r) / delta + 2 - Se a maior cor for
Blue
, a fórmula deve ser (r - g) / delta + 4
Podemos utilizar o delta
para saber se todas as cores são iguais. Afinal, se o maior valor e o menor são iguais, isso significa que todos os valores são iguais, fazendo o delta
ser 0. Então agora, seguindo essas regras, teremos:
function RGBToHSL(r, g, b){
...
if(delta === 0){
h = 0;
}else if(max === r){
h = ((g - b) / delta) % 6;
}else if(max === g){
h = (b - r) / delta + 2;
}else{
h = (r - g) / delta + 4;
}
}
Depois de definir o valor de h
, multiplicamos por 60 e arrendondamos. Como precisamos de um valor entre 0 e 360, precisamos arrumar caso apareça um valor negativo. Para isso, basta somar 360. Isso significa que -90 resultaria em 270.
function RGBToHSL(r, g, b){
...
h = Math.round(h * 60);
if(h < 0){
h += 360;
}
}
Cálculo do Brilho
Agora vamos calcular Lightness
(brilho), já que a saturação depende dele. O cálculo do brilho é a soma do maior valor e do menor valor dividido por 2.
function RGBToHSL(r, g, b){
...
l = (max + min) / 2;
}
Cálculo da Saturação
Agora vamos usar o delta
para calcular Saturation
(saturação). Se o delta for 0, a saturação também deve ser 0.
Se o valor for diferente de 0 devemos pegar 1 e subtrair o valor absoluto do dobro do brilho menos 1. Valor absoluto é basicamente deixar um número negativo na forma positiva. Então -45 ficaria 45.
function RGBToHSL(r, g, b){
...
s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
}
Finalizando a conversão para HSL
Agora que temos os valores de S
e L
, mas eles estão entre 0 e 1. Para converter para valores entre 0% e 100% basta multiplicar por 100. Vamos usar .toFixed(1)
para limitar um número depois da vírgula. Assim um valor 0.3752
vai se tornar 37.5
.
function RGBToHSL(r, g, b){
...
s = +(s * 100).toFixed(1);
l = +(l * 100).toFixed(1);
}
Nossa função completa ficará assim:
function RGBToHSL(r, g, b){
r /= 255;
g /= 255;
b /= 255;
let min = Math.min(r, g, b),
max = Math.max(r, g, b),
delta = max - min,
h = 0,
s = 0,
l = 0;
if(delta === 0){
h = 0;
}else if(max === r){
h = ((g - b) / delta) % 6;
}else if(max === g){
h = (b - r) / delta + 2;
}else{
h = (r - g) / delta + 4;
}
h = Math.round(h * 60);
if(h < 0){
h += 360;
}
l = (max + min) / 2;
s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
s = +(s * 100).toFixed(1);
l = +(l * 100).toFixed(1);
return [h, s, l];
}
Como temos nossas cores em um Array, como [25, 15, 200]
, podemos usar o operador spread para passar esses valores para a função, como:
const color = [25, 15, 200];
RGBToHSL(...color); // retorno: [243, 86, 42.2]
Formação Desenvolvedor React
Conhecer a formaçãoOrdenando Cores
Agora que temos cores, tanto Hexadecimal
quanto RGB
, no formato HSL
, podemos ordená-las. Como vimos, a matiz é definida pelo primeiro valor no modelo HSL
. Então podemos usá-lo para ordenar nossas cores. Para isso basta utilizar o método .sort()
dos Arrays e passar uma função para fazer a comparação entre as cores.
let colors = [
"#fbb735", "#e98931", "#eb403b", "#b32E37", "#6c2a6a",
"#5c4399", "#274389", "#1f5ea8", "#227FB0", "#2ab0c5",
"#39c0b3"
];
// convertendo de hexadecimal para hsl
colors = colors.map(color => {
// de hexadecimal para rgb
color = hexToRGB(color);
// de rgb para hsl
return RGBToHSL(...color);
})
// ordenação pela matiz
colors.sort((a, b) => a[0] - b[0] > 0 ? 1 : -1 );
Resultado
Veja abaixo a implementação. Use os botões para gerar cores e depois para ordenar.
Você vai notar que a ordenação não é 100% perfeita. Isso porque utilizamos apenas a matiz para a ordenação, e o brilho e saturação também são muito importantes para a definição de uma cor. Mas para coisas mais simples esse código funciona muito bem, além de ter servido para aprendermos muitas coisas.
Para mais precisão, prefira utilizar bibliotecas como o color-sorter, onde podemos passar um Array de cores em qualquer formato, até mesmo misturando formatos. Ele também leva em conta coisas como saturação, brilho e transparência.
Veja como o resultado com essa biblioteca é mais preciso:
Há muitas maneiras de ordenar cores, e dependendo do que você quer pode ser necessário dar mais importância para uma propriedade ao invés de outra.