我如何应用不透明度的CSS颜色变量?

我正在设计一个电子应用程序,所以我可以访问CSS变量。我在vars.css中定义了一个颜色变量:

:root {
--color: #f0f0f0;
}

我想在main.css中使用这种颜色,但应用了一些不透明度:

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

我该怎么做呢?我没有使用任何预处理器,只有CSS。我更喜欢全css的答案,但我将接受JavaScript/jQuery。

我不能使用opacity,因为我使用的背景图像不应该是透明的。

236160 次浏览

在CSS中,你应该能够使用rgba值:

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

或者只是设置不透明度:

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

你可以为每种颜色设置特定的变量/值——原始的和不透明的:

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

如果你不能使用这个,你可以使用javascript解决方案,你可以使用这个:

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

的确是可能的与CSS。它只是有点脏,你必须使用渐变。我已经编写了一个小片段作为示例,请注意,对于深色背景,你应该使用黑色不透明度,对于浅色背景-白色背景。

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

你不能获取一个现有的颜色值并应用alpha通道。也就是说,你不能获取一个现有的十六进制值,如#f0f0f0,给它一个alpha组件,并将结果值与另一个属性一起使用。

然而,自定义属性允许你将十六进制值转换为RGB三元组以与rgba()一起使用,将该值存储在自定义属性中(包括逗号!),使用var()将该值替换为带有你想要的alpha值的rgba()函数,这样就可以工作了:

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

虽然这个值作为变量显然是无用的,因为它在任何普通属性中都是无效的,但JavaScript可能会读取它并对其进行操作。

第三节:

如果属性包含一个或多个var()函数,并且这些函数在语法上是有效的,则必须假设整个属性的语法在解析时是有效的。它只在var()函数被替换之后,在计算值时进行语法检查。

这意味着你在上面看到的240, 240, 240值被直接替换到rgba()函数之前中,声明被计算出来。所以这个:

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

这似乎不是有效的CSS,因为rgba()期望不少于四个逗号分隔的数值,变成这样:

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

当然,这是完全有效的CSS。

更进一步,你可以将alpha组件存储在它自己的自定义属性中:

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

代入,得到同样的结果:

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

这允许你有不同的alpha值,你可以在飞行中交换。


1 如果您在一个不支持自定义属性的浏览器中运行代码片段,那么它就是。

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


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

你用0到1之间的任何东西替换不透明度

我知道OP没有使用预处理器,但如果以下信息是这里答案的一部分,我会得到帮助(我还不能评论,否则我会评论@BoltClock答案。

如果你正在使用,例如scss,上面的答案将会失败,因为scss试图用特定于scss的rgba()/hsla()函数编译样式,这需要4个参数。然而,rgba()/hsla()也是css的原生函数,所以你可以使用字符串插值来绕过scss函数。

示例(在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.

如果你像我一样喜欢十六进制颜色,还有另一个解决方案。 十六进制值是6位,之后是alpha值。 00是100%透明99是75%然后它用字母“a1-af”然后“b1-bf”以“ff”结尾,这是100%不透明。< / p >
:root {
--color: #F00;
}


#element {
background: var(--color)f6;
}
我也遇到过类似的情况,但不幸的是,给出的解决方案对我不起作用,因为变量可以是从rgbhslhex的任何东西,甚至是颜色名称。
我现在解决了这个问题,通过将background-coloropacity应用到伪:after:before元素:

.container {
position: relative;
}


.container::before {
content: "";
width: 100%;
height: 100%;
position: absolute;
left: 0;
background-color: var(--color);
opacity: 0.3;
}
样式可能需要稍微改变一下,这取决于背景应该应用到的元素。
此外,它可能并不适用于所有情况,但希望它在某些情况下有所帮助,当其他解决方案无法使用时

<强>编辑: 我刚刚注意到,这个解决方案显然也影响了文本颜色,因为它在目标元素前面创建了一个元素,并对其应用了透明的背景色。
在某些情况下,这可能是一个问题

对于使用rgba()与一般css变量,尝试这样做:

  1. 在:root内部声明颜色,但不要像其他答案那样使用rgb()。只需要写值

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

  1. 使用——color变量使用var()作为其他答案

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

SCSS / sass

你可以只使用十六进制颜色值,而不是为每个通道(0-255)使用8位。

这是我用https://codyhouse.co/blog/post/how-to-combine-sass-color-functions-and-css-variables的初始思想做的

你也可以修改alpha函数,只使用#{$color-name}-rgb,省略生成的*-r, *-g, *-b CSS变量。


结果

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

用法:

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和函数

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

如果你使用暗和光模式,我使用这个样本。我更喜欢分开的颜色和rgb颜色变量分配。所以我每个循环使用两个。我意识到这个解决方案不是纯代码。如果你想干代码,你可以使用一个循环。

$colors-light: (
white: #fff,
black: #0c0d0e,
orange: #f48024,
green: #5eba7d,
blue: #0077cc,
red: #d1383d,
red-100: #e2474c,
red-200: red,
);


$colors-dark: (
black: #fff,
white: #2d2d2d,
orange: #dd7118,
green: #5eba7d,
blue: #0077cc,
red: #aa1c21,
red-100: #c9292e,
red-200: red,
);


@function hexToRGB($hex) {
@return red($hex), green($hex), blue($hex);
}


@mixin generate_colors($colors) {
// Colors
@each $color, $value in $colors {
@if str-slice(#{$value}, 1, 1) == "#" {
--#{$color}: #{$value};
} @else {
--#{$color}: var(--#{$value});
}
}


// RGB Colors
@each $color, $value in $colors {
@if str-slice(#{$value}, 1, 1) == "#" {
--RGB_#{$color}: #{hexToRGB($value)};
} @else {
--RGB_#{$color}: var(--RGB_#{$value});
}
}
}


:root {
@include generate_colors($colors-light);
}


[data-theme="dark"] {
@include generate_colors($colors-dark);
}

干燥的代码

@mixin generate_colors($colors) {
// Colors, RGB Colors
@each $color, $value in $colors {
@if str-slice(#{$value}, 1, 1) == "#" {
--#{$color}: #{$value};
--RGB_#{$color}: #{hexToRGB($value)};
} @else {
--#{$color}: var(--#{$value});
--RGB_#{$color}: var(--RGB_#{$value});
}
}
}

css输出

:root {
--white: #fff;
--RGB_white: 255, 255, 255;
--black: #0c0d0e;
--RGB_black: 12, 13, 14;
--orange: #f48024;
--RGB_orange: 244, 128, 36;
--green: #5eba7d;
--RGB_green: 94, 186, 125;
--blue: #0077cc;
--RGB_blue: 0, 119, 204;
--red: #d1383d;
--RGB_red: 209, 56, 61;
--red-100: #e2474c;
--RGB_red-100: 226, 71, 76;
--red-200: var(--red);
--RGB_red-200: var(--RGB_red);
}


[data-theme="dark"] {
--black: #fff;
--RGB_black: 255, 255, 255;
--white: #2d2d2d;
--RGB_white: 45, 45, 45;
--orange: #dd7118;
--RGB_orange: 221, 113, 24;
--green: #5eba7d;
--RGB_green: 94, 186, 125;
--blue: #0077cc;
--RGB_blue: 0, 119, 204;
--red: #aa1c21;
--RGB_red: 170, 28, 33;
--red-100: #c9292e;
--RGB_red-100: 201, 41, 46;
--red-200: var(--red);
--RGB_red-200: var(--RGB_red);
}


body {
background-color: var(--white);
}


.colors {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-pack: start;
-ms-flex-pack: start;
justify-content: flex-start;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
margin: 50px 0 0 30px;
}


.box {
width: 100px;
height: 100px;
margin-right: 5px;
}


.black {
background-color: var(--black);
}


.white {
background-color: var(--white);
}


.orange {
background-color: var(--orange);
}


.green {
background-color: var(--green);
}


.blue {
background-color: var(--blue);
}


.red {
background-color: var(--red);
}


.red-200 {
background-color: var(--red-200);
}


.black-rgba {
background-color: rgba(var(--RGB_black), 0.5);
}


.white-rgba {
background-color: rgba(var(--RGB_white), 0.5);
}


.orange-rgba {
background-color: rgba(var(--RGB_orange), 0.5);
}


.green-rgba {
background-color: rgba(var(--RGB_green), 0.5);
}


.blue-rgba {
background-color: rgba(var(--RGB_blue), 0.5);
}


.red-rgba {
background-color: rgba(var(--RGB_red), 0.5);
}


.red-rgba-200 {
background-color: rgba(var(--RGB_red-200), 0.5);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div>
<input type="checkbox" id="dark-switch" name="theme" />
<label for="dark-switch">Dark / Light</label>
</div>


<div class="color-box">
<div class="colors">
<div class="box red-200"></div>
<div class="box black"></div>
<div class="box white"></div>
<div class="box orange"></div>
<div class="box green"></div>
<div class="box blue"></div>
<div class="box red"></div>
</div>
<br>


<h1>RGBA</h1>
<div class="colors">
<div class="box red-rgba-200"></div>
<div class="box black-rgba"></div>
<div class="box white-rgba"></div>
<div class="box orange-rgba"></div>
<div class="box green-rgba"></div>
<div class="box blue-rgba"></div>
<div class="box red-rgba"></div>
</div>


</div>


<script>
const dark_switch = document.getElementById("dark-switch");


dark_switch.addEventListener("change", (e) => {
e.target.checked
? document.documentElement.setAttribute("data-theme", "dark")
: document.documentElement.setAttribute("data-theme", "light");
});
</script>
</body>
</html>

你可以使用linear-gradient来修改颜色:

background: linear-gradient(to bottom, var(--your-color) -1000%, var(--mixin-color), 1000%)

$(() => {
const setOpacity = () => {
$('#canvas').css('--opacity', $('#opacity-value').val())
}
const setColor = () => {
$('#canvas').css('--color', $('#color-value').val());
}
$('#opacity-value').on('input', setOpacity);
$('#color-value').on('input', setColor);
setOpacity();
setColor();
})
#canvas {
width: 100px;
height: 100px;
border: 2px solid #000;
--hack: 10000%;
background: linear-gradient( to bottom, var(--color) calc((var(--opacity) - 1) * var(--hack)), transparent calc(var(--opacity) * var(--hack)));
}


#container {
background-image: linear-gradient(45deg, #b0b0b0 25%, transparent 25%), linear-gradient(-45deg, #b0b0b0 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #b0b0b0 75%), linear-gradient(-45deg, transparent 75%, #b0b0b0 75%);
background-size: 20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
padding: 10px;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<div id="container">
<div id="canvas"></div>
</div>
<hr/>
<input type="range" id="opacity-value" min="0" max="1" step="0.1" value="0.5" />
<input type="color" id="color-value" />

相对颜色语法

有了这个允许颜色格式转换的CSS新功能(css-color-5),它也将允许为任何格式的任何颜色添加不透明度,例如RGB(可以对任何其他格式进行相对转换):

html { --color: blue }
.with-opacity { background: rgb(from var(--color) r g b / 50%) }

(在撰写本文时,尚未在浏览器中提供。到达后会更新)

👉Codepen演示