Как применить прозрачность к цветовой переменной CSS?

145

Я разрабатываю приложение в электронном виде, поэтому у меня есть доступ к переменным CSS. Я определил цветовую переменную в vars.css:

:root {
  --color: #f0f0f0;
}

Я хочу использовать этот цвет main.css, но с некоторой непрозрачностью:

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

Как бы я поступил так? Я не использую какой-либо препроцессор, только CSS. Я бы предпочел полностью CSS-ответ, но я приму JavaScript / jQuery.

Я не могу использовать, opacityпотому что я использую фоновое изображение, которое не должно быть прозрачным.

JoshyRobot
источник
Похоже, вы должны использовать более одного элемента ....
epascarello
Я бы предпочел не делать этого, но, похоже, мне придется ... :(
JoshyRobot
4
Ahhhhh !!!!! Это так раздражает! Сейчас почти 2020 год. Палитра цветов получает цвета #hex. alpha / rgba не работает в Sass / Stylus - потому что это не значение rgb. Должен ли я поставить 4 ползунка в моей CMS для каждого цвета?
sheriffderek

Ответы:

242

Вы не можете взять существующее значение цвета и применить к нему альфа-канал. А именно, вы не можете принять существующее шестнадцатеричное значение, такое как#f0f0f0 , присвоить ему альфа-компонент и использовать полученное значение с другим свойством.

Тем не менее, пользовательские свойства позволяют вам преобразовать ваше шестнадцатеричное значение в триплет RGB для использования с ним rgba(), сохранить это значение в пользовательском свойстве (включая запятые!), Заменить это значение с var()помощью 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>

Это кажется слишком хорошим, чтобы быть правдой. 1 Как это работает?

Волшебство заключается в том, что значения пользовательских свойств подставляются как есть при замене var()ссылок в значении свойства, прежде чем вычисляется значение этого свойства. Это означает, что в отношении пользовательских свойств значение --colorв вашем примере вообще не является значением цвета, пока не появится var(--color)выражение где-то, ожидающее значение цвета (и только в этом контексте). Из раздела 2.1 спецификации css-переменных:

Разрешенный синтаксис для пользовательских свойств чрезвычайно разрешающий. Продукция <объявление-значение> соответствует любой последовательности из одного или нескольких токенов, при условии, что последовательность не содержит <bad-string-token>, <bad-url-token>, unmatched <) - token>, <] - token>, или <} - 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.

Сделав еще один шаг вперед, вы можете сохранить альфа-компонент в его собственном пользовательском свойстве:

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

и подставим его с тем же результатом:

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

Это позволяет вам иметь различные альфа-значения, которые вы можете менять на лету.


1 Хорошо, если вы запускаете фрагмент кода в браузере, который не поддерживает пользовательские свойства.

BoltClock
источник
12
Это прекрасно
roberrrt-s
1
@Roberrrt: Это то, что я должен был понять на раннем этапе, на самом деле, видя, как я опубликовал эти ответы ранее.
BoltClock
2
Если мы будем это вар, то почему бы не использовать что - то вроде: .element2 { background-color: rgba(var(--red), var(--low-opacity); }. Таким образом, вы можете полностью использовать использование переменных :).
roberrrt-s
7
К сожалению, значение "240, 240, 240"не может быть изменено с помощью палитры цветов. Это огромная ошибка, когда вам нужно найти правильные цвета для вашего графического интерфейса.
GetFree
1
@ s3c Синтаксис var(--hex-color)99конвертируется в два токена #333333 99(обратите внимание на пробел для разделения токенов), что явно не то, что вам нужно. Пользовательские свойства изначально были определены для копирования токенов, а не строк, и это конечный результат. Это слишком поздно, чтобы исправить это сейчас.
Микко Ранталайнен
20

Я знаю, что 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>

Обратите внимание, что интерполяция строк не будет работать для функций scss, не относящихся к CSS, например lighten(), потому что полученный код не будет функциональным CSS. Это все равно будет действительным scss, так что вы не получите ошибки при компиляции.

SimplyPhy
источник
4
Если вы предпочитаете использовать собственные цветовые функции CSS в ваших файлах Sass .scss, вы можете включить следующие определения функций в начало вашего файла, чтобы переопределить обработку 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
rgbaявляется синонимом в rgbтечение достаточно долгого времени .. Следовательно, вам разрешено отбрасывать «а».
s3c
1
Другой обходной путь для файлов scss заключается в использовании uppercase ( RGB), который затем игнорируется sass. Например: color: RGB(var(--color_rgb), 0.5);. От GitHub
Jono Job
Хороший ответ! Если вы уже определили цвета в шестнадцатеричном виде, вы можете просто добавить этот код, чтобы преобразовать его в пользовательские свойства rgb::root { @each $color, $value in $colors { --#{$color}_rgb: #{red($value), green($value), blue($value)}; } }
Plumpssack
9

Я был в подобной ситуации, но , к сожалению , данные решения не работают для меня, так как переменные могут быть чем - либо от 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;
}

Стили, возможно, придется немного изменить, в зависимости от элемента, к которому следует применить фон.
Также это может не работать для всех ситуаций, но, надеюсь, это поможет в некоторых случаях, когда другие решения не могут быть использованы.

Изменить: Я только что заметил, что это решение, очевидно, также влияет на цвет текста, так как он создает элемент перед целевым элементом и применяет к нему прозрачный фоновый цвет.
Это может быть проблемой в некоторых случаях.

Springrbua
источник
Это не только дает преимущество более гибкой спецификации цвета (например, имени или rgbили HSL), но также позволяет избежать любого конфликта между собственными цветовыми функциями CSS и цветовыми функциями Sass. Смотрите ответ SimplyPhy ниже.
Джим Рэтлифф
1
Я думаю, что лучше использовать, :beforeчтобы вы получили правильный порядок стека, не играя с z-index.
Микко Ранталайнен
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>

roberrrt-ы
источник
Вам не нужно указывать размер фона - градиенты не имеют собственного размера и в результате автоматически растягиваются.
BoltClock
@BoltClock Да, я буквально думал о том, что, когда я отправил это, это было просто немного поиграть в авторучке;). Вычищен сейчас, спасибо!
roberrrt-s
Это умно, я не думал о наложении однотонных градиентов друг на друга, когда отвечал на аналогичный вопрос в прошлом году. Этот вопрос, вероятно, в любом случае носит более общий характер, чем он был написан, и тот, на который я ответил, был для очень конкретного случая использования.
BoltClock
Это действительно не работает, когда фон отличается, теперь я предполагаю белый фон (255,255,255) при применении «непрозрачности». Возможно, по умолчанию используется основной цвет фона OP. Но опять же, белый фон, вероятно, будет соответствовать потребности в более светлых цветах настолько, чтобы люди этого не заметили.
roberrrt-s
1
Я только что обнаружил что-то еще, что довольно невероятно. Я сейчас опубликовал ответ.
BoltClock
1
:root{
--color: 255, 0, 0;
}

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

где вы заменяете непрозрачность между 0 и 1

Пицца Лорд
источник
Это попытка ответить на вопрос? Потому что, если это так, код на самом деле не имеет смысла. Особенно rgba(var(--color), opacity)немного. Тем более что ваше значение пользовательского свойства - это полная запись rgb (). Но также из-за ключевого слова "непрозрачность".
BoltClock
woops мой плохой RGB частей не должно быть в var
Pizza lord
1

SCSS / SASS

Преимущество: вы можете просто использовать шестнадцатеричные значения цвета вместо 8-битного для каждого канала (0-255).

Вот как я сделал это с первоначальной идеей: https://codyhouse.co/blog/post/how-to-combine-sass-color-functions-and-css-variables

Изменить: Вы также можете изменить альфа-функцию, чтобы просто использовать #{$color-name}-rgbи пропустить сгенерированные CSS-переменные * -r, * -g, * -b.


результат

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

Надеюсь, это сэкономит кому-то время.

Стефан Рейн
источник
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>

Dekel
источник
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
Это не решение b / c, если вы хотите, чтобы у BG была прозрачность, но у полного элемента непрозрачность, тогда добавление непрозрачности ко всему бесполезно.
Левидпс
-4

Если вы любите шестнадцатеричные цвета, как я, есть другое решение. Шестнадцатеричное значение составляет 6 цифр, после чего это альфа-значение. 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
Это не работает, хотя было бы отличным решением, если бы это было.
Брэден Рокуэлл Нейпир