如何将不透明度应用于CSS颜色变量?


144

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

:root {
  --color: #f0f0f0;
}

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

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

我将如何去做?我没有使用任何预处理器,只有CSS。我希望使用全CSS的答案,但是我会接受JavaScript / jQuery。

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


所以,像你这样的声音应该使用一个以上的元素....
epascarello

我希望不要,但似乎我可能需要... :(
JoshyRobot

4
啊!真烦人!现在快到2020年了。拾色器获取#hex颜色。alpha / rgba在Sass / Stylus中不起作用-因为它不是rgb值。是否应为每种颜色在CMS中放置4个滑块?
sheriffderek

Answers:


240

您不能采用现有的颜色值并对其应用Alpha通道。也就是说,您不能使用现有的十六进制值(例如)#f0f0f0,给它一个alpha分量,并将结果值与另一个属性一起使用。

但是,自定义属性允许您将十六进制值转换为RGB三元组以与一起使用rgba(),将该值存储在自定义属性中(包括逗号!),使用将该值替换var()rgba()具有所需alpha值的函数,然后它将正常工作:

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

这似乎太好了,难以置信。1它是如何工作的?

神奇之处在于,在计算属性值之前,在替换属性值中的引用时将按原样替换自定义属性的值。这意味着,只要自定义属性而言,价值在你的例子是不是在所有的颜色值,直到一个表达式出现的地方,需要一个颜色值(也只有在这种情况下)。根据css-variables规范的第2.1节var()--colorvar(--color)

自定义属性的允许语法极为宽松。<declaration-value>生产匹配一个或多个令牌的任何序列,只要序列不包含<bad-string-token>,<bad-url-token>,不匹配的<)-token>,<]- token>或<}-token>,或顶级<semicolon-token>令牌或<delim-token>令牌,其值为“!”。

例如,以下是有效的自定义属性:

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

尽管此值显然不能用作变量,但在任何常规属性中均无效,但JavaScript可能会读取并对其起作用。

第3节

如果一个属性包含一个或多个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 是的,如果您正在不支持自定义属性的浏览器中运行代码段。


12
这很漂亮
roberrrt-s

1
@Roberrrt:实际上,这是我早就应该意识到的,因为我之前发布了这些 答案
BoltClock

2
如果要使用此var,为什么不使用类似以下内容:.element2 { background-color: rgba(var(--red), var(--low-opacity); }。这样您就可以充分利用变量的用法了。
roberrrt-s

7
不幸的是,该值"240, 240, 240"不能使用颜色选择器进行编辑。当您需要为GUI找到正确的颜色时,这是一个巨大的损失。
GetFree

1
@ s3c语法var(--hex-color)99被转换为两个标记#333333 99(请注意要分隔标记的空间),这显然不是您想要的。自定义属性最初是为了复制令牌而不是字符串而定义的,这就是最终结果。现在解决此问题为时已晚。
Mikko Rantalainen

19

我知道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>

请注意,字符串插值不适用于非CSS scss函数,例如lighten(),因为生成的代码将不是功能CSS。但是它仍然是有效的scss,因此您不会在编译中收到任何错误。


4
如果您希望在Sass .scss文件中使用本机CSS颜色函数,则可以在文件顶部包含以下函数定义,以覆盖Sass的处理并使其通过: @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

rgbargb相当长一段时间的同义词。.因此,您可以删除“ a”。
s3c

1
scss文件的另一种解决方法是使用大写(RGB),然后被sass忽略。例如:color: RGB(var(--color_rgb), 0.5);。来自GitHub
Jono Job

9

我是在一个类似的情况,但不幸的是给定的解决方案并没有为我工作,因为变量可能是从什么rgbhslhex甚至颜色名称。
我现在通过将background-colorand和opacity应用于伪:after:before元素来解决了这个问题:

.container {
    position: relative;
}

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

样式可能需要稍作更改,具体取决于应应用背景的元素。
同样,它可能无法在所有情况下都起作用,但是希望它在某些情况下会有所帮助,而其他解决方案无法使用。

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


这不仅具有允许更灵活地指定颜色(例如名称rgbHSL)的优点,而且还避免了本地CSS颜色函数和Sass的颜色函数之间的任何冲突。请参阅下面的SimplyPhy的答案
Jim Ratliff

1
我认为最好使用它,:before这样您无需使用即可获得正确的堆叠顺序z-index
Mikko Rantalainen

5

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>


您无需指定背景大小-渐变没有固有大小,因此会自动拉伸。
BoltClock

@BoltClock是的,我从字面上想到,当我发布它时,它只是在Codepen中玩了一点;)。现在收拾了,谢谢!
roberrrt-s 2016年

这很聪明,去年我回答类似的问题时,我还没有想到过将单色渐变彼此叠加。无论如何,这个问题可能更笼统,我回答的是一个非常特定的用例。
BoltClock

但是,当背景不同时,它并没有真正起作用,我现在在应用“不透明度”时假设使用白色背景(255,255,255)。它可能默认为OP的主要背景颜色。但是话又说回来,白色背景可能会适应大多数较浅颜色的需求,以至于人们不会注意到这一点。
roberrrt-s 2016年

1
我刚刚发现了其他令人难以置信的东西。我现在已经发布了答案。
BoltClock

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

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

用0到1之间的任何值替换不透明度


这是在回答问题的尝试吗?因为如果是这样,代码实际上就没有意义。特别是rgba(var(--color), opacity)位。特别是因为您的自定义属性值是整个rgb()表示法。也是因为有“ opacity”关键字。
BoltClock

糟糕,我的rgb部分不应该放在var
Pizza

1

SCSS / SASS

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

这就是我最初的想法: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 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);
}

希望这可以节省一些时间。


1
我喜欢这种方法。谢谢
tonygatta

0

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

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


1
不透明度值将改变,因此为每个不透明度创建变量将很烦人。
JoshyRobot

-1

若要将rgba()与常规css变量一起使用,请尝试以下操作:

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

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

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

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


-3

在CSS中,您应该可以使用rgba值:

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

或只是设置不透明度:

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

1
我无法对rgba值进行硬编码,我正在使用颜色变量。我应该提到我不能使用不透明性,因为我将具有不透明的背景图像。
JoshyRobot

如果您只希望BG具有透明性,而整个元素具有不透明性,然后向所有内容添加不透明性,则这不是解决方案。
Levidps

-4

如果您喜欢像我这样的十六进制颜色,则还有另一种解决方案。十六进制值是6位数字,之后是alpha值。00是100%透明度99是大约75%,则它使用字母“ a1-af”,然后使用“ b1-bf”,以“ ff”结尾,后者是100%不透明。

:root {
--color: #F00;
}

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

1
不幸的是,我认为这行不通。对8位十六进制代码的支持正在开始普及,但是看起来似乎不能与接受的答案一起使用。示例:jsbin.com/nacuharige/edit?css,output
JoshyRobot,

尽管这样做确实是一个很好的解决方案,但这是行不通的。
布雷登·洛克威尔·纳皮尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.