What is the difference between rgb() and rgba() opacity? - css

I found another question on SO about rgb vs rgba that is very similar, but it's missing an answer about the usage of rgb with opacity.
I know the difference between both – rgba is just rgb but with alpha for opacity. The thing is, it has been months or even years that I am using rgb with opacity values. It has always worked for me. rgb(255, 0, 255, 0.5)
Makes me wonder if there's an advantage to use one if both works the same? rgb has been there longer so browser compatibility I suppose is better? Also I was told by a coworker that rgba value will only work for background colors, but then again, I did some tests in codepen and it works on Edge and Chrome.
(I know both are Chrome based both these are the one I have downloaded)
Related question : What are differences between RGB vs RGBA other than 'opacity'
Here is my snippet
/* texts */
.one {
color: rgba(255, 200, 0, .5);
}
.oneFive {
color: rgb(255, 200, 0, .5);
}
/* backgrounds */
.two {
background-color: rgb(255, 0, 255, 0.5);
}
.three {
background-color: rgba(0, 0, 255, 0.5);
}
/* */
/* settings */
/* */
.two, .three {
height: 50px;
}
.two {
margin-top: 30px;
}
.two, .three, .zero {
color: white;
}
.one, .oneFive {
height: 50px;
font-weight: bold;
font-size: 2em;
padding-left: 40px;
padding-top: 20px;
}
body {
background-color: #444;
color: white;
}
.zero {
background-color: darkgreen;
width: 300px;
height: 350px;
position: absolute;
top: 35px;
z-index: -1;
}
dark grey 100% opacity
<div class="zero">dark green 100% opacity</div>
<div class="oneFive">rgb yellow text 70% opacity</div>
<div class="one">rgba yellow text 70% opacity</div>
<div class="two">rgb 50% background opacity</div>
<div class="three">rgba 50% background opacity</div>

Answer as requested:
I'm going to go out on a limb and say it's the browser translating what is essentially an "incorrect" value set in rgb with an opacity value.
If you look in the browser dev tools under the computed tab, you'll notice that the rgb values are computed to rgba (at least in Firefox).
I'm thinking that any browser that supports CSS3 will "fix" the property.
Also I was told by a coworker that rgba value will only work for background colors: Your coworker is wrong.
rgb has been there longer so browser compatibility I suppose is better? I wouldn't say that. You'll never notice a performance hit, but you'll make your browser do less work if it doesn't have to "fix" your incorrect values being passed to the rgb set. Update: rgba is an alias for rgb, so it's really not fixing anything, it's simply passing to rgb anyway.
Here is some documentation on rgb and rgba - specifically the aliasing of the functions:
https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#rgb_colors

Makes me wonder if there's an advantage to use one if both works the same?
It's not about advantage but this is something new defined in the Specification
rgb() and rgba(), and hsl() and hsla() are now aliases of each other (all of them have an optional alpha). ref
And
Also for legacy reasons, an rgba() function also exists, with an identical grammar and behavior to rgb(). ref
So rgba() is meant to disappear and only rgb() should be used but this won't happen because it will create a lot of issues and conflit so rgba() will still be considered and will simply have the same syntax as rgb()
Also note that the new syntax no more contain comma:
rgb() = rgb( <percentage>{3} [ / <alpha-value> ]? ) |
rgb( <number>{3} [ / <alpha-value> ]? )
<alpha-value> = <number> | <percentage>
You should write rgb(255 65 40) or rgb(255 65 40 / 80%) for example but still for legacy reasons the comma syntax is still supported:
For legacy reasons, rgb() also supports an alternate syntax that separates all of its arguments with commas:

Related

Is there a solution to set a linear gradient using one color

On my project, users have the possibility to select an accent color for their profile page (var(--color-main)). Is there a possibility to create a gradient background using only that main color, for example by using the main color + a % applied to this color to make it darker (or lighter) and use this as second color to make the gradient. Is that possible?
.TabsHeader-module--wrapper--BMiDm .TabsHeader-module--bgBlock--qXkLH {
background-color: var(--color-main);
border-radius: 0 0 20rem 0;
height: 21.6rem;
position: absolute;
top: 0;
width: 100%;
}
This is an example with two custom properties defined:
--color is your main color
--alpha is the opacity quota (0-1) applied to --color for having the second gradient color
The background-image style attribute is set using a gradient shading from --color to --color(alpha)
That was made possible with rgba to define colors MDN
:root {
--color: 240, 0, 0;
--alpha: .5;
}
.gradient{
background-image:
linear-gradient(
to right,
rgba(var(--color), 1),
rgba(var(--color), var(--alpha))
);
width: 100%;
height: 200px;
text-align: center;
}
<div class="gradient"></div>
I have found that you can use variable colors with opacity control only if you give the value as RGB decimals, which are 3 numbers (e.g. 240, 240, 240). And later you can give it a 4th value, which will control the opacity of the color (i.e. will make it darker or lighter).
Here is an example:
:root {
--color: 190,190,190;
}
div {
background: linear-gradient(to right, rgba(var(--color), 0.8), rgba(var(--color), 0.3));
}
Thanks to Thankful Teira from codegrepper.com

Purely CSS full hue wheel rainbow border, compatible with Firefox

I am trying to achieve an effect in which the border of an element would go through every color of the rainbow. I was able to find a solution which works very well on Chrome and on Edge, but doesn't work on Firefox due to the lack of support of the conic-gradient property.
Here is the working example I described:
.rainbow-border {
border: double 7px transparent;
background-image: linear-gradient(LightSteelBlue, LightSteelBlue), conic-gradient(#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
background-origin: border-box;
background-clip: content-box, border-box;
}
body {
background-color: LightSlateGrey;
}
#keyframes border-radius-anim {
0% { border-radius: 0px; }
100% { border-radius: 90px; }
}
.main {
width: 80px;
height: 80px;
border-radius: 999px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0px 5px 25px rgba(0, 0, 0, 0.3);
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
animation: border-radius-anim 5s infinite alternate both;
}
<div class="main rainbow-border"></div>
I am working on a project in which different elements have this border, they can have different border width and I should animate it on hover. This solution works perfectly fine for my problem, however not in Firefox and support is required for this browser.
One easy working solution is to replace the conic-gradient(#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000) by some url(url_to_conic_gradient_image), however I am wondering if a purely CSS solution exists, and if so what it looks like.
Using a JS library as a polyfill
As yunzen pointed out, it exists a polyfill for conic-gradient, it works really well from my tests, and it was able to cover this edge case.
Famous Lea Verou made a polyfill: leaverou.github.io/conic-gradient – yunzen
You will have to include 2 javascript files in your project for it to work. What it will do is look for all the conic-gradient css properties in your document and replace those with
a background-image generated based on the conic-gradient property values. So if your css property is loaded at the same time as the DOM, you can use this library and use conic-gradient as if it was supported by all the browsers.
However, if your css is generated after the DOM has loaded, you will have to use another approach which works by generating an image using the library, and then assign it instead of the conic-gradient css function:
var gradient = new ConicGradient({
stops: "gold 40%, #f06 0", // required
repeating: true, // Default: false
size: 400 // Default: Math.max(innerWidth, innerHeight)
});
console.log(gradient.svg); // SVG markup
console.log(gradient.png); // PNG image (fixed dimensions) as a data URL
console.log(gradient.dataURL); // data URL
console.log(gradient.blobURL); // blog URL
Pure css work-around (linear-gradient fallback)
If you are looking for a css-only approach (the main concern being that this library uses some computational power of the javascript thread to generate the images, which can become a big overheat depending on your use case), I will leave here a solution which proposes a pure-css fallback to the lack of support of conic-gradient, but you will lose the conic gradient effect, which may or may not be suited to your use case:
border: double 4px transparent;
background-image: linear-gradient(white, white), linear-gradient(#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
background-image: linear-gradient(white, white), conic-gradient(#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
background-origin: border-box;
background-clip: content-box, border-box;
The line with the conic-gradient will be ignored in the browser in which it isn't supported, leaving the linear gradient as a fallback. So you will lose the conic effect but have a decent visual fallback.
The advantages of the second solution is to free your Javascript thread from generating images to replace the conic-gradient, and as time goes you won't have to update your code if conic-gradient gets supported.

RGBa vs Opacity (Specifically BBC Slider)

I am currently wondering which is the best CSS property to use, Opacity or RGBa? More specifically I am trying to recreate something similar to the famous BBC Home page slider, and it got me thinking why they use Opacity.
In my version I have came across using the following two versions of code:
.left-button {
background: rgb(255, 255, 255) url('../images/left-arrow.png') no-repeat; //FALLBACK
background: rgba(255, 255, 255, 0.4) url('../images/left-arrow.png') no-repeat;
}
or
.left-button {
background: #fff url('../images/left-arrow.png') no-repeat; //FALLBACK
opacity: 0.4;
}
Obviously the second one makes the actual button image opaque too, which is why I assume the BBC has made separate buttons and background masks for the buttons (which in my opinion is unnecessary additional markup).
I'd like to use the first version with RGBa though. Would anyone care to point out why one is better than the other and if there is any compatibility issues I am unaware of?
Opacity is inherited to all child items, RGBa is not. If a child item has a lesser or no opacity, use RGBa.
IE8 and lower does not support RGBa, so you may need an opacity back-up plan.
Neither one is "better" because they do different things, so it depends on what you're trying to accomplish.
opacity sets the opacity for the entire element and all of its contents (text, inline images, etc). RGBa is a way to define a color with a certain level of alpha transparency.
So let's say you have a div:
<div>Hello!</div>
This will make the entire div and its contents ("Hello!") 50% opaque:
div {
background: #000;
color: #fff;
opacity: 0.5;
}
Whereas this will make just the background of the div 50% opaque, while leaving the text at 100% opaque pure white:
div {
background: rgba(0, 0, 0, 0.5);
color: #fff;
}

Sass mixin for background transparency back to IE8

I'm new to Sass and struggling with this. I can't get the color to render in both hex (for IE) and rgba. Every little piece is frustrating me because I haven't mastered the syntax yet, and Google results for Sass are still sparse.
Here's the mixin:
#mixin transparent($hex, $a){
/* for IEGR8 */
background: transparent;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$a}#{$hex},endColorstr=#{$a}#{$hex});
zoom: 1;
/* for modern browsers */
background-color: rgba(#{$hex},.#{$a});
}
Such that #include transparent(#FFF,.4) should produce the nice, browser compatible transparent code below:
background: transparent;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#40FFFFFF,endColorstr=#40FFFFFF);
zoom: 1;
background-color: rgba(100,100,100,.40);
I've been noobing on the following for a couple hours:
The # required for #RGB format.
The . required for rgba alpha.
Both need to be included for the call to rgba(), however the # can't be included for the IE #AARRGGBB or it will look like #AA#RRGGBB, and the . can't be included for IE or it rejects #.AARRGGBB.
Am I missing a much simpler way to do this? Can this be done with Sass string manipulation or any slightly clever color cast function in Sass which handles this for me already?
#mixin transparent($color, $alpha) {
$rgba: rgba($color, $alpha);
$ie-hex-str: ie-hex-str($rgba);
background-color: transparent;
background-color: $rgba;
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ie-hex-str},endColorstr=#{$ie-hex-str});
zoom: 1;
}
NOTE: The ie-hex-str is only available in recent versions, not sure when it was introduced though
I think I encountered a similar problem when I wanted to pass a url to the mixin. Instead of sending only the url I had the send the whole url parameter as a parameter to the mixin. If you understand what I mean?
example:
#mixin bg($url)
background: #000 $url repeat-x
insted of:
#mixin bg($url)
background: #000 url($url) repeat-x
Also, this might not the suited for your application, but I usually work around that problem using opacity:
#mixin transparent_bg($hex, $a){
/* for IEGR8 */
filter:alpha(opacity=$a)
zoom: 1;
/* for modern browsers */
background-color: $hex;
opacity: ($a*10)
}
This probably is as bulletproof as you'll get without a proper shim.
To build on seutje's answer, this lets you use ms-filter transparency if you're doing background-color on IE, but if you if you know the colour of the element behind the element you want to make transparent, you can use Sass's "mix" function to mix the two colours and get fake transparency - for any kind of colour. That means borders and text and all that jive. It's still a manual fallback but it'll give you the exact colour you're trying to simulate with a solid hex.
SCSS:
#mixin alpha-color($foreground-color, $property: 'background-color', $background-context-color: #fff) {
#{$property}: mix(
fade-in($foreground-color, 1),
$background-context-color,
percentage(opacity($foreground-color))
); // Browsers without color opacity
#{$property}: $foreground-color; // Decent browsers
#if $property == 'background-color' {
.lt-ie9 & { // IE8 has background filters; use them instead
#{$property}: transparent;
$ie-hex: ie-hex-str($foreground-color);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#{$ie-hex},endColorstr=#{$ie-hex});
zoom: 1;
}
}
}
To get border-color: rgba(255, 0, 0, 0.5) on a blue background, you'd use it like:
.blue-container {
$color-bg: rgb(0,0,255);
background-color: $color-bg;
.transparent-red-element {
#include alpha-color(rgba(255, 0, 0, .65), border-color, $color-bg);
}
}
Sass automatically turns 100% opacity colors back into a hex code, hence the fade-in of 100%.
The only browsers without colour opacity are IE8 <=8 and Opera <=9.6, and IE 8 has filters so this only helps for colors other than background-color. The principle is that you mix the background and foreground colours together into a flat hex.
ie-hex-str is like a year old now so you'll definitely have it.

Red bg + black field with opacity on 85 = pink text

<style>
* {
background: red;
}
.blackbalk{
background:black;
ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)";
filter:alpha(opacity=85);
-khtml-opacity:.85;
-moz-opacity:.85;
opacity:.85;
width: 985px;
margin: 0 auto;
height:255px;
color: white;
}
</style>
<div class="blackbalk">Text </div>
Now my text gets pink, why?
How can i get it white again?
Greetings
Edit: JS Fiddle to make it clear: http://jsfiddle.net/WFxbH/
You can do it by instead using an rgba background on your element:
Live Demo - this will work "in every browser you care about", and my jsFiddle includes the recommended IE conditional comment to make it also work in that browser.
.blackbalk {
/* Fallback for web browsers that doesn't support RGBa */
background: rgb(0, 0, 0);
/* RGBa with 0.6 opacity */
background: rgba(0, 0, 0, 0.85);
/* For IE 5.5 - 7*/
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D8000000, endColorstr=#D8000000);
/* For IE 8*/
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#D8000000, endColorstr=#D8000000)";
}
Thew, opacity affects the entire element and its contents, not just the background color. If you just want the background color to be 85% black, you should specifiy it with an RGBA color, like so:
.blackbalk {
background: rgba(0, 0, 0, 0.85);
width: 985px;
margin: 0 auto;
height: 255px;
color: white;
}
EDIT: cant over ride the cascading of opacity. Best alternative in my pinion is to use a single pixel 85% opacity black png as the background image. option 2 would be to make the inner content actually outside of the div then position it over but that's a lot finickier. You can even get the transparent png to work in IE without much trouble.
IGNORE:Not positive, as I can't test it right now but I assume the text is becoming translucent with the opacity change. Perhaps if you put your text inside a span with background-color:none and color:white; it might work it out. May have to set the spans opacity to 100% to override.

Resources