27

Is there a way to use CSS variables when specifying gradient colors with transparency, e.g.

:root {
  --accent-color: #dfd0a5;
}

h1{
  background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(red(var(--accent-color)), green(var(--accent-color)), blue(var(--accent-color)), 1));
}
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Manish
  • 1,726
  • 3
  • 23
  • 29

2 Answers2

41

You can use variables, but you can't sample the individual red, green and blue components from a single hex value in CSS.

If you're simply looking to apply an alpha component to an existing RGB triplet, you can specify the entire triplet as a comma-separated list of decimal values instead of a hex value, and substitute it directly into the rgba() function as a single opaque token:

:root {
  --accent-color: 223, 208, 165;
}

h1 {
  background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(var(--accent-color), 1));
}

If you want to specify and control individual R, G and B values with rgba(), you will need to specify a variable for each color component as a decimal value, and reference each variable within the rgba() function like so:

:root {
  --accent-red: 223;
  --accent-green: 208;
  --accent-blue: 165;
}

h1 {
  background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(var(--accent-red), var(--accent-green), var(--accent-blue), 1));
}
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 1
    I am assuming that browser support is not an issue here, but in case anyone is wondering, [only Firefox implements cascading variables at the moment](http://caniuse.com/#feat=css-variables). – BoltClock Apr 12 '15 at 16:12
  • I doubt that even this will be possible. You can replace the whole color value but to synthesize color from variable components you will need something like `calc()` but in color space. – c-smile Apr 12 '15 at 16:24
  • 1
    @c-smile: There is no restriction on which part(s) of a value in a style declaration `var()` may appear in, as long as the value substitutions result in a valid declaration (see http://www.w3.org/TR/css-variables-1/#using-variables). And sure enough, [it works on the only current implementation](http://jsfiddle.net/BoltClock/f5drrLph). – BoltClock Apr 12 '15 at 16:26
  • Interesting, but it seems FF goes against CSS2 spec here that says : "functional notation is 'rgb(' followed by a comma-separated list of three numerical values (either three integer values or three percentage values) followed by ')'" I believe it is spec collision here. – c-smile Apr 12 '15 at 16:36
  • 2
    @c-smile: From the spec link: "If a property contains one or more var() functions, and those functions are syntactically valid, the entire property’s grammar must be assumed to be valid at parse time. It is only syntax-checked at computed-value time, after var() functions have been substituted." So as far as the `rgb()`/`rgba()` grammar is concerned, all it sees is `rgba(223, 208, 165, 1)`, after the substitutions have been performed. If one of the variables was either a number outside the 0-255 range, or not a number at all, then the value would become invalid after substituting that value. – BoltClock Apr 12 '15 at 16:38
  • This requires that the whole property value has to be reparsed each time when variable changes. That should be quite ineffective. – c-smile Apr 12 '15 at 16:47
  • 1
    @c-smile: (You probably meant inefficient, not ineffective.) True - Mozilla hasn't commented on the performance aspect. Either they're not worried about it yet, or they were able to optimize it. – BoltClock Apr 12 '15 at 16:54
  • @BoltClock Ah yes, this indeed is a great example as well! – roberrrt-s Dec 21 '16 at 13:53
1

@boltclock said it all, but you can save a bit of time if your project has a scss preprocessor.

You can do a little tweak to achieve what you want :

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

Then in you css, you can do this:

::root {
    @include defineColorRGB(--accentColor, red(#dfd0a5), green(#dfd0a5), blue(#dfd0a5));
}

You will end up with 4 different css variables, one for your color, and one for each color channel.

Then you can use it almost like you wrote it:

h1{
    background: linear-gradient(
        to right, rgba(255, 255, 255, 0),
        rgba(var(--accent-color-r), var(--accent-color-g), var(--accent-color-b), 1)
    );
}

I find it a very convenient way to initialize my css variables, and use it in most of my projects.

Aurélien B.
  • 498
  • 2
  • 9