How do I apply opacity to a CSS color variable?

此生再无相见时 提交于 2019-12-17 03:59:32

问题


I am designing an app in electron, so I have access to CSS variables. I have defined a color variable in vars.css:

:root {
  --color: #f0f0f0;
}

I want to use this color in main.css, but with some opacity applied:

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

How would I go about doing this? I am not using any preprocesser, only CSS. I would prefer an all-CSS answer, but I will accept JavaScript/jQuery.

I cannot use opacity because I am using a background image that should not be transparent.


回答1:


You can't take an existing color value and apply an alpha channel to it. Namely, you can't take an existing hex value such as #f0f0f0, give it an alpha component and use the resulting value with another property.

However, custom properties allow you to convert your hex value into an RGB triplet for use with rgba(), store that value in the custom property (including the commas!), substitute that value using var() into an rgba() function with your desired alpha value, and it'll just work:

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

This seems almost too good to be true.1 How does it work?

The magic lies in the fact that the values of custom properties are substituted as is when replacing var() references in a property value, before that property's value is computed. This means that as far as custom properties are concerned, the value of --color in your example isn't a color value at all until a var(--color) expression appears somewhere that expects a color value (and only in that context). From section 2.1 of the css-variables spec:

The allowed syntax for custom properties is extremely permissive. The <declaration-value> production matches any sequence of one or more tokens, so long as the sequence does not contain <bad-string-token>, <bad-url-token>, unmatched <)-token>, <]-token>, or <}-token>, or top-level <semicolon-token> tokens or <delim-token> tokens with a value of "!".

For example, the following is a valid custom property:

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

While this value is obviously useless as a variable, as it would be invalid in any normal property, it might be read and acted on by JavaScript.

And section 3:

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.

This means that the 240, 240, 240 value you see above gets substituted directly into the rgba() function before the declaration is computed. So this:

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

which doesn't appear to be valid CSS at first because rgba() expects no less than four comma-separated numeric values, becomes this:

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

which, of course, is perfectly valid CSS.

Taking it one step further, you can store the alpha component in its own custom property:

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

and substitute it, with the same result:

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

This allows you to have different alpha values that you can swap around on-the-fly.


1Well, it is, if you're running the code snippet in a browser that doesn't support custom properties.




回答2:


I know the OP isn't using a preprocessor, but I would have been helped if the following information was part of the answer here (I can't comment yet, otherwise I would have commented @BoltClock answer.

If you are using, e.g. scss, the answer above will fail, because scss attempts to compile the styles with a scss-specific rgba()/hsla() function, which requires 4 parameters. However, rgba()/hsla() are also native css functions, so you can use string interpolation to bypass the scss function.

Example (valid 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>

Note that string interpolation will not work for non-CSS scss functions, such as lighten(), because the resulting code would not be functional CSS. It would still be valid scss though, so you would receive no error in compilation.




回答3:


This is indeed possible with CSS. It's just a bit dirty, and you'll have to use gradients. I've coded a small snippet as example, take note that for dark backgrounds, you should use the black opacity, as for light- the white ones.:

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



回答4:


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

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

where you replace opacity with anything between 0 and 1




回答5:


I was in a similar situation, but unfortunately the given solutions did not work for me, as the variables could be anything from rgb to hsl to hex or even color names.
I solved this issue now, by applying the background-color and the opacity to a pseudo :after element:

.container {
    position: relative;
}

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

The styles might need to be changed a little, depending on the element the background should be applied to.
Also it might not work for all situations, but hopefully it helps in some cases, where the other solutions can't be used.




回答6:


You can set specific variable/value for each color - the original and the one with opacity:

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

If you can't use this and you are ok with javascript solution, you can use this one:

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



回答7:


For using rgba() with general css variable, try this:

  1. Declare your color inside :root, but don't use rgb() as other answers do. just write the value

:root{
  --color : 255,0,0;
  }
  1. Use --color variable using var() as other answers

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



回答8:


SCSS / SASS

This is how I did it with the initial idea of: https://codyhouse.co/blog/post/how-to-combine-sass-color-functions-and-css-variables


Edit

Added another alternative, how to use it.


Result

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

Usage:

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 and functions

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

Hopefully this will save someone some time.




回答9:


In CSS you should be able to either use rgba values:

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

or just set the opacity:

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



回答10:


If you love hex colors like me there is another solution. The hex value is 6 digits after that is the alpha value. 00 is 100% transparency 99 is about 75% then it uses the alphabet 'a1-af' then 'b1-bf' ending with 'ff' which is 100% opaque.

:root {
--color: #F00;
}

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


来源:https://stackoverflow.com/questions/40010597/how-do-i-apply-opacity-to-a-css-color-variable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!