Como aplico opacidade a uma variável de cor CSS?

145

Como estou projetando um aplicativo em elétrons, tenho acesso a variáveis ​​CSS. Eu defini uma variável de cor em vars.css:

:root {
  --color: #f0f0f0;
}

Quero usar essa cor main.css, mas com alguma opacidade aplicada:

#element {
  background: (somehow use var(--color) at some opacity);
}

Como eu faria isso? Não estou usando nenhum pré-processador, apenas CSS. Eu preferiria uma resposta totalmente CSS, mas aceitarei JavaScript / jQuery.

Não posso usar opacityporque estou usando uma imagem de plano de fundo que não deve ser transparente.

JoshyRobot
fonte
Então parece que você deve estar usando mais de um elemento ....
epascarello
Eu preferiria não, mas parece que eu poderia ter para ... :(
JoshyRobot
4
AHHHHH !!!!! Isso é tão chato! É quase 2020 agora. O seletor de cores obtém cores #hex. alpha / rgba não funciona no Sass / Stylus - porque não é um valor de rgb. Devo colocar 4 controles deslizantes no meu CMS para todas as cores?
sheriffderek

Respostas:

242

Você não pode pegar um valor de cor existente e aplicar um canal alfa a ele. Nomeadamente, você não pode #f0f0f0usar um valor hexadecimal existente, como fornecer um componente alfa e usar o valor resultante com outra propriedade.

No entanto, as propriedades personalizadas permitem converter seu valor hexadecimal em um trigêmeo RGB para uso rgba(), armazenar esse valor na propriedade personalizada (incluindo vírgulas!), Substituir esse valor usando var()em uma rgba()função com o valor alfa desejado e ele apenas trabalhe:

:root {
  /* #f0f0f0 in decimal RGB */
  --color: 240, 240, 240;
}

body {
  color: #000;
  background-color: #000;
}

#element {
  background-color: rgba(var(--color), 0.8);
}
<p id="element">If you can see this, your browser supports custom properties.</p>

Isso parece bom demais para ser verdade. 1 Como isso funciona?

A mágica está no fato de que os valores das propriedades customizadas são substituídos como na substituição de var()referências em um valor de propriedade, antes que o valor dessa propriedade seja calculado. Isso significa que, no que diz respeito às propriedades personalizadas, o valor do --colorseu exemplo não é um valor de cor até que uma var(--color)expressão apareça em algum lugar que espere um valor de cor (e somente nesse contexto). Na seção 2.1 da especificação de variáveis ​​css:

A sintaxe permitida para propriedades personalizadas é extremamente permissiva. A produção <declaration-value> corresponde a qualquer sequência de um ou mais tokens, desde que a sequência não contenha <bad-string-token>, <bad-url-token>, inigualável <) - token>, <] - token> ou <} - token> ou tokens <semicolon-token> de nível superior ou tokens <delim-token> com o valor "!".

Por exemplo, a seguir é uma propriedade customizada válida:

--foo: if(x > 5) this.width = 10;

Embora esse valor seja obviamente inútil como uma variável, pois seria inválido em qualquer propriedade normal, ele pode ser lido e utilizado pelo JavaScript.

E seção 3 :

Se uma propriedade contiver uma ou mais funções var () e essas funções forem sintaticamente válidas, a gramática da propriedade inteira deverá ser considerada válida no momento da análise. Ele é verificado apenas na sintaxe no tempo do valor calculado, após a substituição das funções var ().

Isso significa que o 240, 240, 240valor que você vê acima é substituído diretamente na rgba()função antes que a declaração seja computada. Então, é isso:

#element {
  background-color: rgba(var(--color), 0.8);
}

que não parece ser CSS válido no início porque rgba()espera não menos que quatro valores numéricos separados por vírgula, torna-se o seguinte:

#element {
  background-color: rgba(240, 240, 240, 0.8);
}

que, é claro, é CSS perfeitamente válido.

Indo um passo adiante, você pode armazenar o componente alfa em sua própria propriedade customizada:

:root {
  --color: 240, 240, 240;
  --alpha: 0.8;
}

e substitua-o, com o mesmo resultado:

#element {
  background-color: rgba(var(--color), var(--alpha));
}

Isso permite que você tenha valores alfa diferentes que podem ser trocados on-the-fly.


1 Bem, é verdade, se você estiver executando o snippet de código em um navegador que não suporta propriedades personalizadas.

BoltClock
fonte
12
Isso é lindo #
roberrrt-s
1
@Roberrrt: É algo que eu deveria ter percebido desde o início, visto que publiquei essas respostas anteriormente.
BoltClock
2
Se vamos este var, por que não usar algo como: .element2 { background-color: rgba(var(--red), var(--low-opacity); }. Dessa forma, você pode utilizar totalmente o uso de variáveis ​​:).
roberrrt-s
7
Infelizmente, o valor "240, 240, 240"não é editável com um seletor de cores. É uma falta enorme quando você precisa encontrar as cores certas para sua GUI.
GetFree
1
@ s3c A sintaxe var(--hex-color)99é convertida em dois tokens #333333 99(observe o espaço para separar os tokens), o que obviamente não é o que você deseja. As propriedades personalizadas foram originalmente definidas para copiar tokens, não seqüências de caracteres, e este é o resultado final. É muito tarde para consertar isso agora.
Mikko Rantalainen 19/02
20

Sei que o OP não está usando um pré-processador, mas teria sido ajudado se as seguintes informações fizessem parte da resposta aqui (ainda não posso comentar, caso contrário, teria comentado a resposta do @BoltClock.

Se você estiver usando, por exemplo, scss, a resposta acima falhará, porque o scss tenta compilar os estilos com uma função rgba () / hsla () específica do scss, que requer 4 parâmetros. No entanto, rgba () / hsla () também são funções nativas de css, portanto, você pode usar a interpolação de strings para ignorar a função scss.

Exemplo (válido no sass 3.5.0+):

:root {
    --color_rgb: 250, 250, 250;
    --color_hsl: 250, 50%, 50%;
}

div {
    /* This is valid CSS, but will fail in a scss compilation */
    background-color: rgba(var(--color_rgb), 0.5);
    
    /* This is valid scss, and will generate the CSS above */
    background-color: #{'rgba(var(--color_rgb), 0.5)'};
}
<div></div>

Observe que a interpolação de string não funcionará para funções scss não CSS, como lighten(), porque o código resultante não seria CSS funcional. No entanto, ainda seria um scss válido, portanto você não receberá nenhum erro na compilação.

SimplyPhy
fonte
4
Se você preferir usar funções de cores CSS nativas nos arquivos .scss do Sass, poderá incluir as seguintes definições de funções na parte superior do arquivo para substituir o tratamento do Sass e fazê-las passar: @function rgb($args...) { @return #{'rgb(#{$args})'}; } @function rgba($args...) { @return #{'rgba(#{$args})'}; } @function hsl($args...) { @return #{'hsl(#{$args})'}; } @function hsla($args...) { @return #{'hsla(#{$args})'}; }`` ``
lunelson
rgbaé sinônimo de já faz um rgbbom tempo. Portanto, você pode largar o "a".
s3c 19/02
1
Outra solução alternativa para arquivos scss é usar uppercase ( RGB) que é ignorado pelo sass. Por exemplo: color: RGB(var(--color_rgb), 0.5);. De GitHub
Jono Job
Boa resposta! Se você já definiu as cores em hexadecimal, pode simplesmente adicionar esse código para convertê-lo nas propriedades personalizadas de rgb::root { @each $color, $value in $colors { --#{$color}_rgb: #{red($value), green($value), blue($value)}; } }
Plumpssack
9

Eu estava em uma situação semelhante, mas, infelizmente, as soluções dadas não funcionou para mim, como as variáveis poderia ser qualquer coisa, desde rgbque hsla hexou mesmo nomes de cores.
Resolvi esse problema agora, aplicando oe background-coloro opacitya um pseudo :afterou :beforeelemento:

.container {
    position: relative;
}

.container:before {
    content: "";
    width: 100%;
    height: 100%;
    position: absolute;
    left: 0;
    background-color: var(--color);
    opacity: 0.3;
}

Os estilos podem precisar ser alterados um pouco, dependendo do elemento ao qual o plano de fundo deve ser aplicado.
Também pode não funcionar para todas as situações, mas espero que ajude em alguns casos, onde as outras soluções não podem ser usadas.

Edit: Acabei de notar que essa solução obviamente também afeta a cor do texto, pois cria um elemento na frente do elemento de destino e aplica uma cor de fundo transparente a ele.
Isso pode ser um problema em alguns casos.

Springrbua
fonte
Isso não apenas tem a vantagem de permitir uma especificação mais flexível da cor (por exemplo, um nome ou rgbou HSL), mas também evita qualquer conflito entre as funções de cores CSS nativas e as funções de cores do Sass. Veja a resposta do SimplyPhy abaixo.
Jim Ratliff
1
Eu acho que é melhor usar :beforepara que você obtenha a ordem correta de empilhamento sem brincar z-index.
Mikko Rantalainen 19/02
5

Isso é realmente possível com CSS . Está um pouco sujo e você terá que usar gradientes. Codifiquei um pequeno trecho como exemplo, observe que, para fundos escuros, você deve usar a opacidade em preto, como em claro - os brancos:

:root {
  --red: rgba(255, 0, 0, 1);
  --white-low-opacity: rgba(255, 255, 255, .3);
  --white-high-opacity: rgba(255, 255, 255, .7);
  --black-low-opacity: rgba(0, 0, 0, .3);
  --black-high-opacity: rgba(0, 0, 0, .7);
}

div {
	width: 100px;
	height: 100px;
	margin: 10px;
}
    
    
.element1 {
	background: 
        linear-gradient(var(--white-low-opacity), var(--white-low-opacity)) no-repeat,
	linear-gradient(var(--red), var(--red)) no-repeat;
}

.element2 {
	background: 
        linear-gradient(var(--white-high-opacity), var(--white-high-opacity)) no-repeat,
	linear-gradient(var(--red), var(--red)) no-repeat;
}
    
.element3 {
	background: 
        linear-gradient(var(--black-low-opacity), var(--black-low-opacity)) no-repeat,
	linear-gradient(var(--red), var(--red)) no-repeat;
}

.element4 {
	background: 
        linear-gradient(var(--black-high-opacity), var(--black-high-opacity)) no-repeat,
	linear-gradient(var(--red), var(--red)) no-repeat;
}
<div class="element1">hello world</div>
<div class="element2">hello world</div>
<div class="element3">hello world</div>
<div class="element4">hello world</div>

roberrrt-s
fonte
Você não precisa especificar o tamanho do plano de fundo - os gradientes não têm tamanho intrínseco e, como resultado, se estendem automaticamente.
BoltClock
@BoltClock Sim, eu literalmente pensei nisso quando publiquei, era apenas um pouco de brincadeira no codepen;). Limpo agora, obrigado!
precisa saber é o seguinte
Isso é inteligente, não pensei em colocar gradientes de cores sólidas um sobre o outro quando respondi a uma pergunta semelhante no ano passado. De qualquer maneira, essa pergunta é provavelmente mais geral da maneira como foi escrita, a que respondi foi para um caso de uso muito específico.
BoltClock
No entanto, não funciona realmente quando os fundos são diferentes, agora assumo um fundo branco (255.255.255) ao aplicar a 'opacidade'. Possivelmente poderia ter como padrão a cor principal do plano de fundo do OP. Mas, novamente, o fundo branco provavelmente atenderá à necessidade de cores mais claras, a ponto de as pessoas não perceberem isso.
precisa saber é o seguinte
1
Acabei de descobrir outra coisa que é incrível. Agora eu postei uma resposta.
BoltClock
1
:root{
--color: 255, 0, 0;
}

#element{
    background-color: rgba(var(--color), opacity);
}

onde você substitui a opacidade por algo entre 0 e 1

Pizza lord
fonte
É uma tentativa de responder à pergunta? Porque se assim for, o código realmente não faz sentido. Particularmente a parte rgba(var(--color), opacity). Especialmente porque o valor da sua propriedade personalizada é toda a notação rgb (). Mas também por causa da palavra-chave "opacidade".
BoltClock
woops meu mau partes rgb não deve estar no var
Pizza senhor
1

SCSS / SASS

Vantagem: você pode apenas usar valores de cores hexadecimais, em vez de usar os 8 bits para cada canal (0-255).

É assim que eu fiz isso com a ideia inicial de: https://codyhouse.co/blog/post/how-to-combine-sass-color-functions-and-css-variables

Editar: Você também pode modificar a função alfa para usar #{$color-name}-rgbe omitir as variáveis ​​CSS * -r, * -g, * -b geradas.


Resultado

body {
  --main-color: rgb(170, 68, 204);
  --main-color-rgb: 170,68,204;
  --main-color-r: 170;
  --main-color-g: 68;
  --main-color-b: 204;
}

.button-test {
  // Generated from the alpha function
  color: rgba(var(--main-color-r), var(--main-color-g), var(--main-color-b), 0.5);
  // OR (you wrote this yourself, see usage)
  color: rgba(var(--main-color-rgb), 0.5);
}

Uso:

body {
    @include defineColorRGB(--main-color, #aa44cc);
}

.button-test {
  // With alpha function:
  color: alpha(var(--main-color), 0.5);
  // OR just using the generated variable directly
  color: rgba(var(--main-color-rgb), 0.5);
}

Mixin e funções

@mixin defineColorRGB($color-name, $value) {
    $red: red($value);
    $green: green($value);
    $blue: blue($value);
    #{$color-name}: unquote("rgb(#{$red}, #{$green}, #{$blue})");
    #{$color-name}-rgb: $red,$green,$blue;
    #{$color-name}-r: $red;
    #{$color-name}-g: $green;
    #{$color-name}-b: $blue;
}

// replace substring with another string
// credits: https://css-tricks.com/snippets/sass/str-replace-function/
@function str-replace($string, $search, $replace: '') {
    $index: str-index($string, $search);
    @if $index {
        @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
    }
    @return $string;
}

@function alpha($color, $opacity) {
    $color: str-replace($color, 'var(');
    $color: str-replace($color, ')');
    $color-r: var(#{$color+'-r'});
    $color-g: var(#{$color+'-g'});
    $color-b: var(#{$color+'-b'});
    @return rgba($color-r, $color-g, $color-b, $opacity);
}

Espero que isso poupe tempo a alguém.

Stefan Rein
fonte
1
Eu gosto dessa abordagem. Obrigado
tonygatta
0

Você pode definir variáveis ​​/ valores específicos para cada cor - o original e o com opacidade:

:root {
  --color: #F00;
  --color-opacity: rgba(255, 0, 0, 0.5);
}
#a1 {
  background: var(--color);
} 
#a2 {
  background: var(--color-opacity);
}
<div id="a1">asdf</div>
<div id="a2">asdf</div>

Se você não pode usar isso e está bem com a solução javascript, pode usar esta:

$(function() {
  $('button').click(function() {
    bgcolor = $('#a2').css('backgroundColor');
    rgb_value = bgcolor.match(/\d+,\s?\d+,\s?\d+/)[0]
    $('#a2').css('backgroundColor', 'rgba(' + rgb_value + ', 0.5)');
  });
});
:root {
  --color: #F00;
}
#a1 {
  background: var(--color);
} 
#a2 {
  background: var(--color);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a1">asdf</div>
<div id="a2">asdf</div>
<button>Click to change opacity</button>

Dekel
fonte
1
O valor da opacidade será alterado, portanto, seria irritante criar uma variável para cada opacidade.
JoshyRobot 13/10
-1

Para usar rgba () com a variável css geral, tente o seguinte:

  1. Declare a sua cor inside: root, mas não use rgb () como outras respostas. basta escrever o valor

:root{
  --color : 255,0,0;
  }

  1. Use a variável --color usando var () como outras respostas

#some-element {
  color : rgba(var(--color),0.5);
}

Dani Fadli
fonte
-3

No CSS, você poderá usar os valores rgba:

#element {
  background: rgba(240, 240, 240, 0.5);
}

ou apenas defina a opacidade:

#element {
  background: #f0f0f0;
  opacity: 0.5;    
}
Patrick H.
fonte
1
Não consigo codificar um valor rgba, estou usando variáveis ​​de cores. Eu deveria ter mencionado que não posso usar opacidade porque terei uma imagem de plano de fundo que não deve ser transparente.
JoshyRobot
Esta não é uma solução b / c, se você deseja que o BG tenha transparência, mas que o elemento completo tenha opacidade, então adicionar opacidade a tudo não é útil.
Levidps
-4

Se você gosta de cores hexagonais como eu, há outra solução. O valor hexadecimal é de 6 dígitos depois que esse é o valor alfa. 00 é 100% de transparência 99 é cerca de 75% e, em seguida, usa o alfabeto 'a1-af' e depois 'b1-bf', terminando com 'ff', que é 100% opaco.

:root {
--color: #F00;
}

#element {
background: var(--color)f6;
}
Seth M
fonte
1
Infelizmente, acho que isso não funciona. O suporte ao código hexadecimal de 8 dígitos está começando a se espalhar, mas não parece que o truque usado com a resposta aceita funcione com eles. Exemplo: jsbin.com/nacuharige/edit?css,output
JoshyRobot 25/08
Isso não funciona, embora fosse uma ótima solução se funcionasse.
Braden Rockwell Napier