Como verificar se uma string é uma representação de cor hexadecimal válida?

120

Por exemplo:

AA33FF = cor hexadecimal válida

Z34FF9 = cor hexadecimal inválida (contém Z)

AA33FF11 = cor hexadecimal inválida (possui caracteres extras)

Alex
fonte
10
dependendo do contexto, o último pode ser uma cor válida, se incluir alfa no AARRGGBBformato.
J. Holmes

Respostas:

283
/^#[0-9A-F]{6}$/i.test('#AABBCC')

Para elaborar:

^ ->corresponde ao início de
# ->um hash
[0-9A-F] ->qualquer inteiro de 0 a 9 e qualquer letra de A a F
{6} ->o grupo anterior aparece exatamente 6 vezes
$ ->corresponde ao fim
i ->ignora maiúsculas

Se você precisar de suporte para códigos HEX de 3 caracteres, use o seguinte:

/^#([0-9A-F]{3}){1,2}$/i.test('#ABC')

A única diferença aqui é que

 [0-9A-F]{6}

é substituído por

([0-9A-F]{3}){1,2}

Isso significa que em vez de corresponder a exatamente 6 caracteres, ele corresponderá a exatamente 3 caracteres, mas 1 ou 2 vezes. Permitindo ABCe AABBCC, mas nãoABCD

Royi Namir
fonte
18
Por definição, isso está correto, mas os códigos com comprimento 3 também são válidos para interpretação do navegador. color: #f00;será interpretado como vermelho (# ff0000) também.
Smamatti
13
ou outra forma:/^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test("#f00")
J. Holmes
8
Eu também adicionaria /^#([0-9a-f]{3}){1,2}$/ià mistura.
MasterAM
1
@AndresSepar /^#[0-9A-F]{3,6}$/i.test('#aabb')também passa, mas #aabbnão é uma cor hexadecimal válida.
Roman Boiko,
3
var isOk = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/i.test('#aabbcc '); @RomanBoiko isso é certo! Obrigado!
Andres Separ,
32

// regular function
function isHexColor (hex) {
  return typeof hex === 'string'
      && hex.length === 6
      && !isNaN(Number('0x' + hex))
}

// or as arrow function (ES6+)
isHexColor = hex => typeof hex === 'string' && hex.length === 6 && !isNaN(Number('0x' + hex))

console.log(isHexColor('AABBCC'))   // true
console.log(isHexColor('AABBCC11')) // false
console.log(isHexColor('XXBBCC'))   // false
console.log(isHexColor('AAXXCC'))   // false

Essa resposta costumava lançar falsos positivos porque, em vez de Number('0x' + hex), costumava parseInt(hex, 16).
parseInt()irá analisar desde o início da string até chegar a um caractere que não está incluído na raiz ( 16). Isso significa que ele pode analisar strings como 'AAXXCC', porque começa com 'AA'.

Number(), por outro lado, só analisará se toda a string corresponder à raiz. Agora, Number()não leva um parâmetro de raiz, mas felizmente, você pode prefixar literais de número para obter um número em outros raios.

Aqui está uma tabela para esclarecimento:

╭─────────────┬────────────┬────────┬───────────────────╮
 Radix        Characters  Prefix  Will output 27    
╞═════════════╪════════════╪════════╪═══════════════════╡
 Binary       0-1         0b      Number('0b11011') 
 Octal        0-7         0o      Number('0o33')    
 Decimal      0-9         -       -                 
 Hexadecimal  0-9A-F      0x      Number('0x1b')    
╰─────────────┴────────────┴────────┴───────────────────╯
fflorent
fonte
6
+1 bcs muito melhor de ler e mais rápido de entender do que um regex
Chris,
10
@Chris 'porque' também é muito melhor de ler e mais rápido de entender do que 'bcs' ;-)
Chris,
1
@Chris: Eu me acostumei tanto com 'bcs' que não faz diferença. de qualquer forma, meu comentário foi feito como um elogio, então seja feliz.
Chris
12
Isso está errado: parseInt ('abcZab', 16) irá exibir o número e passar no teste
Salvador Dali
1
@fflorent Porque parseInttomará "abcZab", descubra que "Z"é inválido (para o radical 16), e ignore-o e qualquer coisa depois dele. Em seguida, pega o início "abc"e o converte em 2748(que também é o resultado de parseInt("abcZab", 16)provar que essa é a lógica acontecendo). Como o nome indica, parseInt analisa uma string. Exatamente como se você estivesse analisando um número com unidades com uma raiz de 10, como parseInt("10px", 10), você obteria 10. Você pode vê-lo descrito aqui: es5.github.io/#x15.1.2.2 (etapa 11)
Ian
8

Isso pode ser um problema complicado. Após várias tentativas, encontrei uma solução bastante limpa. Deixe o navegador fazer o trabalho por você.

Etapa 1: crie um div com o estilo de borda definido como nenhum. O div pode ser posicionado fora da tela ou pode ser qualquer div em sua página que não use as bordas.

Etapa 2: defina a cor da borda como uma string vazia. O código pode ser parecido com este:

e=document.getElementbyId('mydiv');
e.style.borderColor="";

Etapa 3: defina a cor da borda com a cor da qual você não tem certeza.

e.style.borderColor=testcol;

Etapa 4: verifique se a cor realmente mudou. Se testcol for inválido, nenhuma alteração ocorrerá.

col2=e.style.borderColor;
if(col2.length==0) {alert("Bad Color!");}

Etapa 5: limpe depois de definir a cor de volta para uma string vazia.

e.style.borderColor="";

O Div:

<div id="mydiv" style="border-style:none; position:absolute; left:-9999px; top:-9999px;"></div>

Agora, a função JavaScript:

function GoodColor(color)
{
   var color2="";
   var result=true;
   var e=document.getElementById('mydiv');
   e.style.borderColor="";
   e.style.borderColor=color;
   color2=e.style.borderColor;
   if (color2.length==0){result=false;}
   e.style.borderColor="";
   return result;
}

Nesse caso, a função está retornando uma resposta verdadeira / falsa para a pergunta, a outra opção é fazer com que ela retorne um valor de cor válido. O valor da cor original, o valor de borderColor ou uma string vazia no lugar de cores inválidas.

Terry Prothero
fonte
IMO, esta não é uma solução limpa, no mínimo
Gust van de Wal
5

Se você estiver tentando usá-lo em HTML, tente usar este padrão diretamente:

 pattern="^#+([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$"

gostar

<input id="hex" type="text" pattern="^#+([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$" />

Isso dará uma validação para corresponder ao formato solicitado.

Mohit Dhawan
fonte
2
function validColor(color){
  var $div = $("<div>");
  $div.css("border", "1px solid "+color);
  return ($div.css("border-color")!="")
}

https://gist.github.com/dustinpoissant/22ce25c9e536bb2c5a2a363601ba261c

Nota: Isso requer jQuery

Isso funciona para TODOS os tipos de cores, não apenas para valores hexadecimais. Também não anexa elementos desnecessários à árvore DOM.

Dustin Poissant
fonte
Agradável e fácil e funciona muito bem. Pessoalmente, adicionei if (hexString.indexOf ('#') == -1) {return false; } para verificar se há um hash como uma verificação rudimentar de que a cor era um valor hexadecimal
365SplendidSuns
1

Se você precisa de uma função para dizer se uma cor é válida, você também pode fazer com que ela forneça algo útil - os valores calculados dessa cor - e retornar nulo quando não for uma cor válida. Aqui está minha tentativa de obter uma função compatível (Chrome54 e MSIE11) para obter os valores RGBA de uma "cor" em qualquer um dos formatos - seja 'verde', ou '#FFF', ou '# 89abcd' ou 'rgb (0,0,128) ', ou' rgba (0, 128, 255, 0,5) '.

/* getRGBA:
  Get the RGBA values of a color.
  If input is not a color, returns NULL, else returns an array of 4 values:
   red (0-255), green (0-255), blue (0-255), alpha (0-1)
*/
function getRGBA(value) {
  // get/create a 0 pixel element at the end of the document, to use to test properties against the client browser
  var e = document.getElementById('test_style_element');
  if (e == null) {
    e = document.createElement('span');
    e.id = 'test_style_element';
    e.style.width = 0;
    e.style.height = 0;
    e.style.borderWidth = 0;
    document.body.appendChild(e);
  }

  // use the browser to get the computed value of the input
  e.style.borderColor = '';
  e.style.borderColor = value;
  if (e.style.borderColor == '') return null;
  var computedStyle = window.getComputedStyle(e);
  var c
  if (typeof computedStyle.borderBottomColor != 'undefined') {
    // as always, MSIE has to make life difficult
    c = window.getComputedStyle(e).borderBottomColor;
  } else {
    c = window.getComputedStyle(e).borderColor;
  }
  var numbersAndCommas = c.replace(new RegExp('[^0-9.,]+','g'),'');
  var values = numbersAndCommas.split(',');
  for (var i = 0; i < values.length; i++)
    values[i] = Number(values[i]);
  if (values.length == 3) values.push(1);
  return values;
}
Ábaco
fonte
0

Adicione uma verificação de comprimento para garantir que você não obtenha um falso positivo

function isValidHex(testNum){
  let validHex = false;
  let numLength = testNum.length;
  let parsedNum = parseInt(testNum, 16);
  if(!isNan(parsedNum) && parsedNum.length===numLength){
     validHex = true;
  }
  return validHex;

}

rotato poti
fonte