如何将不透明度应用于 CSS 颜色变量?
Posted
技术标签:
【中文标题】如何将不透明度应用于 CSS 颜色变量?【英文标题】:How do I apply opacity to a CSS color variable? 【发布时间】:2017-02-21 23:07:33 【问题描述】:我正在用电子设计一个应用程序,所以我可以访问 CSS 变量。我在vars.css
中定义了一个颜色变量:
:root
--color: #f0f0f0;
我想在main.css
中使用这种颜色,但应用了一些不透明度:
#element
background: (somehow use var(--color) at some opacity);
我该怎么做呢?我没有使用任何预处理器,只有 CSS。我更喜欢全 CSS 的答案,但我会接受 javascript/jQuery。
我不能使用opacity
,因为我使用的背景图片不应该是透明的。
【问题讨论】:
听起来你应该使用多个元素.... 我不想这样做,但似乎我可能不得不... :( 啊啊啊啊!!!!!!这太烦人了!现在快2020年了。颜色选择器获取#hex 颜色。 alpha / rgba 在 Sass/Stylus 中不起作用 - 因为它不是 rgb 值。我应该在我的 CMS 中为每种颜色放置 4 个滑块吗? 【参考方案1】:在 CSS 中,您应该能够使用 rgba 值:
#element
background: rgba(240, 240, 240, 0.5);
或者只是设置不透明度:
#element
background: #f0f0f0;
opacity: 0.5;
【讨论】:
我无法硬编码 rgba 值,我正在使用颜色变量。我应该提到我不能使用不透明度,因为我将有一个不应该是透明的背景图像。 如果您只希望 BG 具有透明度但整个元素具有不透明度,那么这不是一个解决方案 b/c,那么为所有内容添加不透明度是没有帮助的。【参考方案2】:您可以为每种颜色设置特定的变量/值 - 原始颜色和具有不透明度的颜色:
: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>
【讨论】:
不透明度值会发生变化,因此为每个不透明度创建一个变量会很烦人。【参考方案3】:这确实可以通过 CSS 实现。它只是有点脏,你必须使用渐变。我编写了一个小的 sn-p 作为示例,请注意,对于深色背景,您应该使用黑色不透明度,对于浅色 - 白色的。:
: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 是的,当我发布它时,我真的想到了,这只是在代码笔中玩耍;)。现在清理了,谢谢! 这很聪明,当我去年回答similar question 时,我没有想到将纯色渐变层叠在一起。无论如何,这个问题的编写方式可能更笼统,我回答的是一个非常具体的用例。 当背景不同时它实际上不起作用,我现在假设在应用“不透明度”时是白色背景 (255,255,255)。它可能默认为 OP 的主要背景颜色。但话又说回来,白色背景可能适合大多数较浅颜色的需求,以至于人们不会注意到这一点。 我刚刚发现了一些非常不可思议的东西。我现在已经发布了答案。【参考方案4】:您不能采用现有的颜色值并将 Alpha 通道应用到它。也就是说,您不能将现有的十六进制值(例如 #f0f0f0
)赋予它一个 alpha 分量并将结果值与另一个属性一起使用。
但是,自定义属性允许您将十六进制值转换为 RGB 三元组以与 rgba()
一起使用,将该值存储在自定义属性中(包括逗号!),使用 var()
将该值替换为 @987654329 @ 具有您想要的 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它是如何工作的?
神奇之处在于,当替换属性值中的var()
引用时,按原样替换自定义属性的值,在计算该属性值之前 .这意味着就自定义属性而言,您示例中的--color
的值根本不是颜色值直到var(--color)
表达式出现在某个需要颜色值的地方(并且仅在这种情况下)。来自 css-variables 规范的 section 2.1:
自定义属性允许的语法非常宽松。
产生式匹配一个或多个令牌的任何序列,只要该序列不包含 、 、不匹配的 、 或 或*** 令牌或 具有“!”值的令牌。
例如,以下是一个有效的自定义属性:
--foo: if(x > 5) this.width = 10;
虽然这个值作为变量显然是无用的,因为它在任何普通属性中都是无效的,但它可能会被 JavaScript 读取并执行。
还有section 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好吧,如果你在不支持自定义属性的浏览器中运行代码 sn-p。
【讨论】:
这很漂亮 @Roberrrt:事实上,正如我之前发布的these answers 那样,我应该早早意识到这一点。 很遗憾,"240, 240, 240"
的值无法使用颜色选择器进行编辑。当您需要为您的 GUI 找到正确的颜色时,这是一个巨大的失误。
@s3c 语法var(--hex-color)99
被转换为两个标记#333333 99
(注意分隔标记的空间),这显然不是你想要的。自定义属性最初被定义为复制标记,而不是字符串,这是最终结果。现在解决这个问题为时已晚。
@s3c:好消息是 CSS Color 5 引入了一些很酷的新函数来操作现有的十六进制值,包括更改它们的 alpha 通道:drafts.csswg.org/css-color-5/#colormodify【参考方案5】:
:root
--color: 255, 0, 0;
#element
background-color: rgba(var(--color), opacity);
将不透明度替换为 0 到 1 之间的任何值
【讨论】:
这是在尝试回答问题吗?因为如果是这样,代码就没有意义了。特别是rgba(var(--color), opacity)
位。特别是因为您的自定义属性值是整个 rgb() 符号。但也因为“不透明”关键字。
糟糕,rgb 部分不应该在 var 中【参考方案6】:
我知道 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,因此您在编译时不会收到任何错误。
【讨论】:
如果您更喜欢在您的 Sass .scss 文件中使用原生 CSS 颜色函数,您可以在文件顶部包含以下函数定义以覆盖 Sass 的处理并使其通过:@987654325 @@function rgba($args...) @return #'rgba(#$args)';
@function hsl($args...) @return #'hsl(#$args)';
@function hsla($args...) @return #'hsla(#$args)';
````
rgba
是rgb
的同义词已经有一段时间了。因此你可以去掉“a”。
scss 文件的另一种解决方法是使用大写字母 (RGB
),然后被 sass 忽略。例如:color: RGB(var(--color_rgb), 0.5);
。来自GitHub
不错的答案!如果您已经定义了十六进制颜色,您只需添加以下代码即可将其转换为自定义 rgb 属性::root @each $color, $value in $colors --#$color_rgb: #red($value), green($value), blue($value);
在 npm 上使用最新的 sass
包,这种解决方法似乎不再需要【参考方案7】:
如果你像我一样喜欢十六进制颜色,还有另一种解决方案。 十六进制值是 6 位数字,之后是 alpha 值。 00 是 100% 的透明度 99 是大约 75% 然后它使用字母 'a1-af' 然后 'b1-bf' 以 'ff' 结尾,它是 100% 不透明的。
:root
--color: #F00;
#element
background: var(--color)f6;
【讨论】:
不幸的是,我认为这行不通。 8 位十六进制代码支持开始普及,但看起来与接受的答案一起使用的技巧不适用于他们。示例:jsbin.com/nacuharige/edit?css,output 这行不通,但如果可以的话,这将是一个很好的解决方案。 截至我发帖时,现在近 94% 的当前使用的浏览器都可以使用此功能 [caniuse.com/css-rrggbbaa].我已经走这条路了,因为我所有的颜色变量都已经保存为 HEX 值,所以添加额外的 2 个字符来指示 alpha 是完美的解决方案。 @Rillus,您能提供工作示例吗?似乎不支持这种结构。 我现在意识到我的实现与这张海报使用的不匹配,并且 CSS 变量连接即var(--color)f6
不起作用(在这种情况下产生的值是 #f0f0f0 f6
,它是无效的)。我的成功工作结果是使用 Vue3 并引用 js 导入的颜色属性,例如:`background-color: v-bind(this.colourHex + 'f6');` 为混淆道歉。【参考方案8】:
我遇到了类似的情况,但不幸的是,给定的解决方案对我不起作用,因为变量可以是从 rgb
到 hsl
到 hex
的任何东西,甚至是颜色名称。
我现在解决了这个问题,将background-color
和opacity
应用于伪:after
或:before
元素:
.container
position: relative;
.container::before
content: "";
width: 100%;
height: 100%;
position: absolute;
left: 0;
background-color: var(--color);
opacity: 0.3;
样式可能需要稍作更改,具体取决于应应用背景的元素。 此外,它可能不适用于所有情况,但希望它在某些情况下有所帮助,因为其他解决方案无法使用。
编辑: 我刚刚注意到,这个解决方案显然也会影响文本颜色,因为它会在目标元素前面创建一个元素并为其应用透明背景色。 在某些情况下,这可能是个问题。
【讨论】:
这不仅具有允许更灵活地指定颜色的优点(例如,名称,或rgb
或HSL
),而且还避免了原生 CSS 颜色函数和 Sass 的颜色之间的任何冲突职能。请参阅下面的SimplyPhy's answer。
我认为最好使用:before
,这样您就可以在不使用z-index
的情况下获得正确的堆叠顺序。【参考方案9】:
要使用带有通用 css 变量的 rgba(),试试这个:
-
在 :root 中声明你的颜色,但不要像其他答案那样使用 rgb()。只写值
:root
--color : 255,0,0;
-
使用 --color 变量使用 var() 作为其他答案
#some-element
color : rgba(var(--color),0.5);
【讨论】:
【参考方案10】: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 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);
希望这可以节省一些时间。
【讨论】:
【参考方案11】:如果您使用深色和浅色模式,我使用此示例。我更喜欢将颜色和 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>
【讨论】:
这是一篇令人难以置信的帖子!感谢所有这些代码。我基本上把它全部复制到我自己的项目中。对于任何来这里遇到问题的人,我确实必须改变一件事。最初声明 SASS 颜色变量时,您需要在名称周围加上引号,如下所示:$colors-light: ( 'color-primary': #2F302F, 'color-primary-variant': #4E4E4E,
【参考方案12】:
您可以使用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" />
【讨论】:
【参考方案13】:如果您想使用 HEX 格式的原色并使用 SCSS,请尝试以下操作:
$primary-transparentize-08: transparentize($primary, 0.8);
然后
background-color: $primary-transparentize-08;
【讨论】:
这是 SCSS 变量,不适用于 CSS 变量以上是关于如何将不透明度应用于 CSS 颜色变量?的主要内容,如果未能解决你的问题,请参考以下文章