Come posso applicare l'opacità a una variabile di colore CSS?


145

Sto progettando un'app in elettrone, quindi ho accesso alle variabili CSS. Ho definito una variabile di colore in vars.css:

:root {
  --color: #f0f0f0;
}

Voglio usare questo colore main.css, ma con qualche opacità applicata:

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

Come potrei fare per fare questo? Non sto usando alcun preprocessore, solo CSS. Preferirei una risposta tutta CSS, ma accetterò JavaScript / jQuery.

Non posso usare opacityperché sto usando un'immagine di sfondo che non dovrebbe essere trasparente.


Quindi sembra che dovresti usare più di un elemento ....
Epascarello

Preferirei non farlo, ma sembra che dovrei ... :(
JoshyRobot,

4
AHHHHH !!!!! Questo è così fastidioso! Sono quasi il 2020 adesso. Il selettore colore ottiene i colori #hex. alpha / rgba non funziona in Sass / Stylus - perché non è un valore rgb. Devo inserire 4 cursori nel mio CMS per ogni singolo colore?
Sheriffderek,

Risposte:


242

Non puoi prendere un valore di colore esistente e applicare un canale alfa ad esso. Vale a dire, non puoi prendere un valore esadecimale esistente come #f0f0f0, dargli un componente alfa e usare il valore risultante con un'altra proprietà.

Tuttavia, le proprietà personalizzate consentono di convertire il valore esadecimale in una tripletta RGB da utilizzare con rgba(), archiviare quel valore nella proprietà personalizzata (comprese le virgole!), Sostituire quel valore usando var()in una rgba()funzione con il valore alfa desiderato e lo farà solo lavoro:

: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>

Sembra quasi troppo bello per essere vero. 1 Come funziona?

La magia sta nel fatto che i valori delle proprietà personalizzate vengono sostituiti come quando si sostituiscono i var()riferimenti in un valore di proprietà, prima che il valore di quella proprietà venga calcolato. Ciò significa che, per quanto riguarda le proprietà personalizzate, il valore di --colornel tuo esempio non è affatto un valore di colore fino a quandovar(--color) un'espressione non appare da qualche parte che si aspetta un valore di colore (e solo in quel contesto). Dalla sezione 2.1 delle specifiche delle variabili css:

La sintassi consentita per le proprietà personalizzate è estremamente permissiva. La produzione <declaration-value> corrisponde a qualsiasi sequenza di uno o più token, purché la sequenza non contenga <bad-string-token>, <bad-url-token>, senza pari <) - token>, <] - token> o <} - token> o token <semicolon-token> di livello superiore o token <delim-token> con valore "!".

Ad esempio, la seguente è una proprietà personalizzata valida:

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

Sebbene questo valore sia ovviamente inutile come variabile, poiché non sarebbe valido in qualsiasi proprietà normale, potrebbe essere letto e applicato da JavaScript.

E sezione 3 :

Se una proprietà contiene una o più funzioni var () e tali funzioni sono sintatticamente valide, l'intera grammatica della proprietà deve essere considerata valida al momento dell'analisi. Viene verificato solo alla sintassi al momento del valore calcolato, dopo che le funzioni var () sono state sostituite.

Ciò significa che il 240, 240, 240valore che vedi sopra viene sostituito direttamente nella rgba()funzione prima che la dichiarazione venga calcolata. Così questo:

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

che all'inizio non sembra essere un CSS valido perché rgba()prevede non meno di quattro valori numerici separati da virgola, diventa questo:

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

che, ovviamente, è un CSS perfettamente valido.

Facendo un passo ulteriore, è possibile memorizzare il componente alfa nella propria proprietà personalizzata:

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

e sostituirlo, con lo stesso risultato:

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

Ciò consente di avere valori alfa diversi che è possibile scambiare al volo.


1 Bene, lo è, se stai eseguendo lo snippet di codice in un browser che non supporta proprietà personalizzate.


12
È bellissimo
roberrrt-s il

1
@Roberrrt: È qualcosa che avrei dovuto capire presto, infatti, visto che avevo pubblicato queste risposte in precedenza.
BoltClock

2
Se stiamo andando questo var, perché non usare qualcosa come: .element2 { background-color: rgba(var(--red), var(--low-opacity); }. In questo modo è possibile utilizzare appieno l'utilizzo delle variabili :).
roberrrt-s,

7
Sfortunatamente, il valore "240, 240, 240"non è modificabile con un selettore di colori. Questa è una grande mancanza quando devi trovare i colori giusti per la tua GUI.
GetFree

1
@ s3c La sintassi var(--hex-color)99viene convertita in due token #333333 99(notare lo spazio per separare i token) che ovviamente non è ciò che si desidera. Le proprietà personalizzate sono state originariamente definite per copiare token, non stringhe e questo è il risultato finale. È troppo tardi per risolvere questo problema ora.
Mikko Rantalainen,

20

So che l'OP non utilizza un preprocessore, ma sarei stato aiutato se le seguenti informazioni facessero parte della risposta qui (non posso ancora commentare, altrimenti avrei commentato la risposta di @BoltClock.

Se si utilizza, ad es. Scss, la risposta precedente non riuscirà, poiché scss tenta di compilare gli stili con una funzione rgba () / hsla () specifica di scss, che richiede 4 parametri. Tuttavia, rgba () / hsla () sono anche funzioni css native, quindi puoi usare l'interpolazione di stringhe per bypassare la funzione scss.

Esempio (valido in 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>

Si noti che l'interpolazione di stringhe non funzionerà per le funzioni scss non CSS, ad esempio lighten()perché il codice risultante non sarebbe CSS funzionale. Sarebbe comunque valido scss, quindi non si riceverà alcun errore nella compilazione.


4
Se si preferisce utilizzare le funzioni di colore CSS native nei file .scss di Sass, è possibile includere le seguenti definizioni di funzioni nella parte superiore del file per sovrascrivere la gestione di Sass e farle passare: @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è sinonimo da rgbun po 'di tempo ormai. Ti è quindi permesso di rilasciare la "a".
s3c

1
Un'altra soluzione alternativa per i file scss è l'uso di maiuscole ( RGB) che viene quindi ignorato da sass. Ad esempio: color: RGB(var(--color_rgb), 0.5);. Da GitHub
Jono Job il

Bella risposta! Se hai già definito i colori in esadecimale, puoi semplicemente aggiungere questo codice per convertirlo nelle proprietà personalizzate di rgb::root { @each $color, $value in $colors { --#{$color}_rgb: #{red($value), green($value), blue($value)}; } }
Plumpssack

9

Io ero in una situazione simile, ma purtroppo le soluzioni indicate non ha funzionato per me, come le variabili potrebbero essere qualsiasi cosa, da rgba hsla hexo anche nomi di colori.
Ho risolto questo problema ora, applicando il background-colore il opacitya uno pseudo :aftero :beforeelemento:

.container {
    position: relative;
}

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

Potrebbe essere necessario modificare leggermente gli stili, a seconda dell'elemento su cui dovrebbe essere applicato lo sfondo.
Inoltre, potrebbe non funzionare in tutte le situazioni, ma si spera che in alcuni casi aiuti, in cui le altre soluzioni non possono essere utilizzate.

Modifica: ho appena notato che questa soluzione influisce ovviamente anche sul colore del testo, in quanto crea un elemento davanti all'elemento di destinazione e applica un colore di sfondo trasparente ad esso.
Questo potrebbe essere un problema in alcuni casi.


Ciò non solo ha il vantaggio di consentire una specifica più flessibile del colore (ad es. Un nome o rgbo HSL), ma evita anche qualsiasi conflitto tra le funzioni di colore CSS native e le funzioni di colore di Sass. Vedi la risposta di SimplyPhy di seguito.
Jim Ratliff,

1
Penso che sia meglio usare in :beforemodo da ottenere il giusto ordine di sovrapposizione senza giocarci z-index.
Mikko Rantalainen,

5

Questo è davvero possibile con i CSS . È solo un po 'sporco e dovrai usare le sfumature. Ho codificato un piccolo frammento come esempio, prendi nota che per gli sfondi scuri, dovresti usare l'opacità nera, come per la luce - quelli bianchi .:

: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>


Non è necessario specificare la dimensione dello sfondo: i gradienti non hanno dimensioni intrinseche e di conseguenza si allungheranno automaticamente.
BoltClock

@BoltClock Sì, ci ho pensato letteralmente quando l'ho pubblicato, era solo un po 'di gioco nel codepen;). Pulito ora, grazie!
roberrrt-s,

È intelligente, non avevo pensato di sovrapporre sfumature di colore solido l'una sull'altra quando ho risposto a una domanda simile l'anno scorso. Questa domanda è probabilmente più generica comunque nel modo in cui è stata scritta, quella a cui ho risposto è stata per un caso d'uso molto specifico.
BoltClock

In realtà non funziona quando gli sfondi sono diversi, ora presumo uno sfondo bianco (255.255.255) quando si applica l'opacità. Potrebbe eventualmente essere impostato sul colore di sfondo principale di OP. Ma ancora una volta, lo sfondo bianco probabilmente si adatta alla necessità della maggior parte dei colori più chiari nella misura in cui le persone non lo noteranno.
roberrrt-s,

1
Ho appena scoperto qualcos'altro di incredibile. Ora ho pubblicato una risposta.
BoltClock

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

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

dove sostituisci l'opacità con qualsiasi valore compreso tra 0 e 1


È un tentativo di rispondere alla domanda? Perché se è così, il codice non ha davvero senso. In particolare la rgba(var(--color), opacity)punta. Soprattutto perché il valore della proprietà personalizzata è l'intera notazione rgb (). Ma anche a causa della parola chiave "opacità".
BoltClock

fa il mio male le parti rgb non dovrebbero essere nel var
Pizza Lord

1

SCSS / SASS

Vantaggio: è possibile utilizzare solo valori di colore esadecimali, invece di utilizzare l'8 bit per ogni canale (0-255).

È così che ho fatto con l'idea iniziale di: https://codyhouse.co/blog/post/how-to-combine-sass-color-functions-and-css-variables

Modifica: puoi anche modificare la funzione alfa per usare #{$color-name}-rgbe omettere semplicemente le variabili CSS generate * -r, * -g, * -b.


Risultato

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 funzioni

@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);
}

Spero che questo salverà qualcuno un po 'di tempo.


1
Mi piace questo approccio. Grazie
tonygatta il

0

Puoi impostare variabili / valori specifici per ciascun colore: l'originale e quello con l'opacità:

: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 non puoi usarlo e stai bene con la soluzione JavaScript, puoi usare questo:

$(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>


1
Il valore di opacità cambierà, quindi sarebbe fastidioso creare una variabile per ogni opacità.
JoshyRobot,

-1

Per usare rgba () con la variabile css generale, prova questo:

  1. Dichiara il tuo colore dentro: root, ma non usare rgb () come fanno altre risposte. basta scrivere il valore

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

  1. Usa la variabile --color usando var () come altre risposte

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


-3

In CSS dovresti essere in grado di utilizzare i valori rgba:

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

o semplicemente imposta l'opacità:

#element {
  background: #f0f0f0;
  opacity: 0.5;    
}

1
Non riesco a codificare un valore rgba, sto usando variabili di colore. Avrei dovuto menzionare che non posso usare l'opacità perché avrò un'immagine di sfondo che non dovrebbe essere trasparente.
JoshyRobot,

Questa non è una soluzione b / c se vuoi solo che la BG abbia trasparenza ma l'intero elemento abbia opacità quindi aggiungere opacità a tutto non è utile.
Levidps,

-4

Se ami i colori esadecimali come me, c'è un'altra soluzione. Il valore esadecimale è di 6 cifre dopo che è il valore alfa. 00 è trasparenza al 100% 99 è circa il 75%, quindi usa l'alfabeto 'a1-af' quindi 'b1-bf' che termina con 'ff' che è opaco al 100%.

:root {
--color: #F00;
}

#element {
background: var(--color)f6;
}

1
Sfortunatamente, non penso che funzioni. Il supporto del codice esadecimale a 8 cifre sta iniziando a diffondersi, ma non sembra che il trucco usato con la risposta accettata funzioni con loro. Esempio: jsbin.com/nacuharige/edit?css,output
JoshyRobot

Questo non funziona, anche se sarebbe un'ottima soluzione se lo facesse.
Braden Rockwell Napier,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.