20

Is there a method in which I can change the opacity of a border which is being set to inherit it's color from currentColor? i.e. inherit currentColor in #inner2 and set it's opacity to 0.25.

Searching for a pure css solution please.

For example, something which resembles the following:

#outer{
  color: rgba(255,0,0,1);
}

.inner{
  display: block;
  width: 100%;
  height: 10px;
  margin-bottom: 5px;
  border: 2px solid currentColor;
}

#inner2{
  /* This is where I want to inherit current color */
  /* ... but still set it to 0.25 opacity */
  border-color: rgba(255,0,0,0.25);
}
<div id='outer'>
  <div id='inner1' class='inner'></div>
  <div id='inner2' class='inner'></div>
</div>
Zze
  • 18,229
  • 13
  • 85
  • 118
  • 1
    impossible... you can use tricks like `before/after` which inherit the color and then you can set `opacity` on those. – vsync Jul 13 '17 at 08:25
  • If you want to use like that , sass scss will the best for you !!! – Jack jdeoel Jul 13 '17 at 08:56
  • Related - [How do I apply opacity to a CSS color variable?](https://stackoverflow.com/q/40010597/104380) – vsync Nov 08 '20 at 09:37
  • i thought of a stupid thing, how about making the outer opacity 0.25 so the one inheriting it receives it clean no need to change, then for the outer you layer 4 of it lol – encryptoferia Jun 13 '23 at 08:37

4 Answers4

13

color-mix

caniuse support table

color-mix can be used to mix currentColor with other colors (like transparent):

html {
  display: grid;
  place-items: center;
  height: 100vh;
  box-sizing: border-box;
  font: 700 6em Arial;
  
  /* actual fun: */
  color: Salmon;
  background: color-mix(in srgb, currentColor 20%, transparent);
  border: 20px solid color-mix(in srgb, currentColor 50%, transparent);
}
AWESOME

Previous answer:

You are confusing currentColor value with inherit which is the default. you don't use currentColor for border properties because that it the default value for the border.

#inner1 and #inner2 both inherit from the closest parent which has a color set to it (red) and the border is using that color by default.

Below solution will work 100% of the time, regardless of the color's source
(inline style attribute, external CSS or distant ancestor inheritance):

#outer{ color:red; }
#inner1, #inner2{ 
    padding: 2em; 
    margin-top: 1em;  
}
#inner1{ border:5px solid; } 

#inner2{ position:relative; }

#inner2::before{  
  content:'';
  position:absolute;
  top:0;
  right:0;
  bottom:0;
  left:0;
  border:5px solid;
  opacity:.5;
}
<div id='outer'>
  <div id='inner1'>inner 1</div>
  <div id='inner2'>inner 2</div>
</div>

Also, see my other answer here which uses cutting-edge syntax.

vsync
  • 118,978
  • 58
  • 307
  • 400
  • hmmm ok yeah, interesting... this seems like a feasible solution. Is `#inner2` smaller than `#inner1` in the example - not sure why though>? – Zze Jul 13 '17 at 08:33
  • yes it acts different since the border is not a real part of the div, but is *over* it, so it does not take any space. you can solve this by using `box-shadow` on both, instead of `border`, or just compensate using different `padding` on the second `div` – vsync Jul 13 '17 at 08:37
  • @Zze - give `#inner1` - `box-shadow: 0 0 0 5px inset;` instead of border :) – vsync Jul 13 '17 at 08:45
7

You can use css-variables to achieve similar behaviour:

#outer{
  --border-r: 255;
  --border-g: 0;
  --border-b: 0;
  color: rgba(var(--border-r),var(--border-g),var(--border-b),1);
}

.inner{
  display: block;
  width: 100%;
  height: 10px;
  margin-bottom: 5px;
  border: 2px solid;
}

#inner2{
  color: rgba(var(--border-r),var(--border-g),var(--border-b),0.25);
}
<div id='outer'>
  <div id='inner1' class='inner'></div>
  <div id='inner2' class='inner'></div>
</div>
fen1x
  • 5,616
  • 6
  • 28
  • 39
  • you don't need to write `currentColor` in the border, it's meaningless. – vsync Jul 13 '17 at 08:38
  • Thx, I forgot to remove it =) – fen1x Jul 13 '17 at 08:40
  • while this works, this solution is not *flexible*, since the colors might come from an inline `style` attribute or external CSS file, or if the color is coming from an unknown distant ancestor (so you cannot exactly know where to set up the variables) – vsync Jul 13 '17 at 11:14
  • I was inspired by this, I *do* think this does work, just needed some tweaks. Check out this demo: https://codepen.io/nicetransition/pen/bGWOVMN – Kevin Mack Aug 09 '21 at 15:52
  • @vsync `currentColor` is the color of the text of that same element, it's not meaningless. If you want the border to be the same as `color:` property than use currentColor – Vitim.us Apr 28 '22 at 03:36
2

You can now achieve this in a more direct way, at least in modern browsers, using the color-mix function.

Example:

#outer {
  color: rgba(255,0,0,1);
}

.inner {
  display: block;
  width: 100%;
  height: 10px;
  margin-bottom: 5px;
  border: 2px solid currentColor;
}

#inner2 {
  border-color: color-mix(in srgb, currentColor 25%, transparent);
}
<div id='outer'>
  <div id='inner1' class='inner'></div>
  <div id='inner2' class='inner'></div>
</div>

You can choose a colour space (I chose SRGB for you here), and the proportion for the mixture. If you leave out the proportion, it defaults to 50%.

Note, however, that if the current colour is already partially transparent, this will make it more transparent; this does not replace the alpha channel. For that we need to wait for relative colors (another part of CSS Color Level 5).

tremby
  • 9,541
  • 4
  • 55
  • 74
  • Yes to `color-mix`!. I can now have hundreds of elements on the page with a translucent layer on them without blowing up my RAM usage. `opacity` creates a new `stacking context` (layer) per element which isn't always the best practice. – ShortFuse Aug 29 '23 at 14:06
1

Check this out:

:root {
  --color-r: 0;
  --color-g: 0;
  --color-b: 0;
  --color-a: 1;
}

[class*=-color] {
  color: rgba(var(--color-r), var(--color-g), var(--color-b), var(--color-a));
}

[class*=-background] {
  --background-r: var(--color-r);
  --background-g: var(--color-g);
  --background-b: var(--color-b);
  --background-color-a: var(--color-a);
  background-color: rgba(var(--color-r), var(--color-g), var(--color-b), var(--color-a));
}

[class*=dark] {
  --color-r: 0;
  --color-g: 0;
  --color-b: 0;
}

[class*=light] {
  --color-r: 255;
  --color-g: 255;
  --color-b: 255;
}

[class*=primary] {
  --color-r: 200;
  --color-g: 2;
  --color-b: 33;
}

[class*=secondary] {
  --color-r: 102;
  --color-g: 102;
  --color-b: 102;
}

[class*="--alpha-0"], [class*="--alpha-00"] {
  --color-a: 0;
}

[class*="--alpha-10"] {
  --color-a: .1;
}

[class*="--alpha-20"] {
  --color-a: .2;
}

[class*="--alpha-30"] {
  --color-a: .3;
}

[class*="--alpha-40"] {
  --color-a: .4;
}

[class*="--alpha-50"] {
  --color-a: .5;
}

[class*="--alpha-60"] {
  --color-a: .6;
}

[class*="--alpha-70"] {
  --color-a: .7;
}

[class*="--alpha-80"] {
  --color-a: .8;
}

[class*="--alpha-90"] {
  --color-a: .9;
}

[class*="--alpha-100"] {
  --color-a: 1;
}
Kevin Mack
  • 96
  • 5