856

I am using something similar to the following code:

<div style="opacity:0.4; background-image:url(...);">
    <div style="opacity:1.0;">
        Text
    </div>
</div>

I expected this to make the background have an opacity of 0.4 and the text to have 100% opacity. Instead they both have an opacity of 0.4.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
John Wheal
  • 9,908
  • 6
  • 29
  • 39
  • 9
    This is my solution: `
    Text
    `
    – Beamer Sep 12 '18 at 19:52
  • It's too bad there's no **background-opacity** property for BG *images*. I've got a responsive situation where a background that slides underneath text on smaller devices needs to be more subtle and transparent. I'm probably going to have to change the HTML structure and give the BG its own dedicated div just because of this. It's funny to me because the property **[background-blend-mode](https://developer.mozilla.org/en-US/docs/Web/CSS/background-blend-mode)** exists, but no such thing for opacity (something you'd be more likely to want to change, and prob tweak when changing blend mode). – Mentalist Aug 08 '23 at 06:31

8 Answers8

1369

Children inherit opacity. It'd be weird and inconvenient if they didn't.

You can use a translucent PNG file for your background image, or use an RGBa (a for alpha) color for your background color.

Example, 50% faded black background:

<div style="background-color:rgba(0, 0, 0, 0.5);">
   <div>
      Text added.
   </div>
</div>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
AlienWebguy
  • 76,997
  • 17
  • 122
  • 145
  • 10
    A more in-depth tutorial can be found here: http://robertnyman.com/2010/01/11/css-background-transparency-without-affecting-child-elements-through-rgba-and-filters/ – Iain Fraser Mar 14 '13 at 00:56
  • 22
    Is it possible to set alpha through a separate css rule? – jayarjo Apr 11 '14 at 08:02
  • 3
    No, it's a single channel of the color value, and the color value is assigned to the css rule. – AlienWebguy Apr 11 '14 at 17:29
  • 3
    @jayarjo `rgba(255,255,255,0.6)` is equivalent to colour neutral fade out of the background. – LateralFractal Mar 04 '15 at 07:13
  • Nice ! background-color:rgba(0, 0, 0, 0.06) can go to the second decimal for a lighter transparency – Anyone_ph Nov 12 '15 at 10:00
  • 47
    It's not really correct to say that "Children inherit opacity". They don't. It's just that if a child is contained in a parent with opacity, the child will have opacity: 1, but the parent applies it's opacity to itself including all it's children. – stephband Jan 15 '16 at 16:11
  • @jayarjo Does HSL do what you want to do: https://en.wikipedia.org/wiki/HSL_and_HSV ? The CSS would be `hsl(a,b,c) ` or 1hsla(a,b,c,z)`. See http://www.w3schools.com/cssref/css_colors_legal.asp for CSS colouring options. – Ken Sharp Feb 13 '16 at 21:12
  • AlienWebguy, you said "Children inherit opacity. It'd be weird and inconvenient if they didn't." Well, now it's weird that they do, starting in Chrome 53, and all browsers following suit. Check this out: https://bugs.chromium.org/p/chromium/issues/detail?id=646993 Please voice your opinion on this if it matters to you (in the issue, and to the public-fx@w3.org mailing list with topic [css-transforms]). – trusktr Sep 17 '16 at 20:13
  • 1
    Note that `RRGGBBaa` notation isn't supported in Microsoft browsers: https://www.caniuse.com/#feat=css-rrggbbaa But `rgba()` notation is. – Protector one Dec 07 '18 at 11:26
  • 2
    @Protectorone also, rgba(.., .., .., **50%**) ist not supported in IE11. Use 0.5 instead. – Volodymyr Kotylo Jul 02 '21 at 10:22
252

You can use pseudo-elements ::before or ::after to get a semi-transparent background and you can do this with just one container. Use something like this:

<article>
  Text.
</article>

Then apply some CSS:

article {
  position: relative;
  z-index: 1;
}

article::before {
  content: "";
  position: absolute;
  top: 0; 
  left: 0;
  width: 100%; 
  height: 100%;  
  opacity: .4; 
  z-index: -1;
  background: url(path/to/your/image);
}

Example:

body {
  background: red;
}

article {
  position: relative;
  z-index: 1;
}

article:before {
  content: " ";
  position: absolute;
  top: 0; 
  left: 0;
  width: 100%; 
  height: 100px;  
  opacity: .4; 
  z-index: -1;
  background: url(https://31.media.tumblr.com/8ec07e49f33088c2e32c158ca4262eb2/tumblr_n5wav6Tz4R1st5lhmo1_1280.jpg);
}
<article>
  Text.
</article>

Note: You might need to adjust the z-index values.

daniels
  • 4,961
  • 2
  • 22
  • 11
  • Actually it does work in all new browsers and IE 9 and up. Take a look here [example](http://codepen.io/anon/pen/alfLj) – daniels Jun 18 '14 at 20:33
  • 17
    I prefer this solution over the one with rgba because it works with both images and background-colors. – BillyTom Sep 26 '14 at 06:27
  • 5
    The accepted answer is correct but this creative solution answers the OP more directly. Editing your background image to be a semi-transparent png/gif/etc.. is even more correct. Opacity takes a bit more juice to render. – Patrick Borkowicz Dec 05 '14 at 19:11
  • Of course, if you're using css3, then the rgba CSS style is likely supported and you don't have to write so much code. You could replace this entire thing with... like... literally one line of css. – dudewad Feb 04 '15 at 06:02
  • 6
    @dudewad The OP wants the opacity to apply to a background image. – daniels Feb 04 '15 at 09:48
  • Though @Patrick has the best solution in my opinion. You have to prep the image anyways, why not just make it transparent to begin with. There's a point where front end devs start to over-automate things, and stuff like asset management should be done on the creative end, in my opinion. Though, using this solution to make *any* background transparent is obviously preferable in certain circumstances, so its contextual. – dudewad Feb 04 '15 at 17:37
  • 1
    This works, however if you want to change the background color of a pseudo element via javascript - you won't be able to since it is part of the shadow-dom. – Adam Cooper Dec 14 '16 at 15:14
  • :before rule will also need display:block; if like me container:before has previously been set to another display option (its a generic layout throughout most of my site but ive put this as a style block on the specific page) – CodingInTheUK Nov 06 '17 at 23:27
  • This :before method may be the only solution that would work with a dynamic background color element. Say, adding a hover lighten effect (background color white, opacity .1 or .2 or so) to an element whose color is not known to you. Without knowing what color the element is, you can't change its transparency. – eon Apr 08 '20 at 12:59
64

The following methods can be used to solve your problem:

  1. CSS alpha transparency method (doesn't work in Internet Explorer 8):

    #div{background-color:rgba(255,0,0,0.5);}
    
  2. Use a transparent PNG image according to your choice as background.

  3. Use the following CSS code snippet to create a cross-browser alpha-transparent background. Here is an example with #000000 @ 0.4% opacity

    .div {
        background:rgb(0,0,0);
        background: transparent\9;
        background:rgba(0,0,0,0.4);
        filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#66000000,endColorstr=#66000000);
        zoom: 1;
    }
    .div:nth-child(n) {
        filter: none;
    }
    

For more details regarding this technique, see this, which has an online CSS generator.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Achyuth Ajoy
  • 641
  • 5
  • 3
  • The css tag is called `background-color` not `background` – Wilt Feb 16 '16 at 16:06
  • 12
    @Wilt the css rule background-color is a subrule of background. Similar to border, margin, and padding, all background subrules can be set inside of background in one line instead of separately. Using background in this instance is what you want though so you can override other background subrules. – David R. Jun 10 '16 at 14:57
44

I would do something like this

<div class="container">
  <div class="text">
    <p>text yay!</p>
  </div>
</div>

CSS:

.container {
    position: relative;
}

.container::before {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    background: url('/path/to/image.png');
    opacity: .4;
    content: "";
    z-index: -1;
}

It should work. This is assuming you are required to have a semi-transparent image BTW, and not a color (which you should just use rgba for). Also assumed is that you can't just alter the opacity of the image beforehand in Photoshop.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pete Lada
  • 1,298
  • 10
  • 12
  • do you have to set z-index: -1 on #bgd ? otherwise it'll make the entire thing transparent – windmaomao Jun 18 '15 at 03:58
  • not `z-index`, but `bgd` div element needs to be before the `text` element – T.Todua Feb 07 '16 at 18:16
  • 1
    `pointer-events: none;` instead of `z-index: -1` on the `::before` pseudo-element will allow the mouse to click through it to the actual element while still showing the pseudo on top. – OXiGEN Sep 27 '20 at 07:41
14

You can use Sass' transparentize.

I found it to be the most useful and plain to use.

transparentize(rgba(0, 0, 0, 0.5), 0.1) => rgba(0, 0, 0, 0.4)
transparentize(rgba(0, 0, 0, 0.8), 0.2) => rgba(0, 0, 0, 0.6) 

See more: #transparentize($color, $amount) ⇒ Sass::Script::Value::Color

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ilan weissberg
  • 658
  • 1
  • 7
  • 13
8
.transbg{/* Fallback for web browsers that don't support RGBa */
background-color: rgb(0, 0, 0);
/* RGBa with 0.6 opacity */
background-color: rgba(0, 0, 0, 0.6);
/* For IE 5.5 - 7*/
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);
/* For IE 8*/
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)";}
Wael Wafik
  • 121
  • 1
  • 3
5

This is because the inner div has 100% of the opacity of the div it is nested in (which has 40% opacity).

In order to circumvent it, there are a few things you could do.

You could create two separate divs like so:

<div id="background"></div>
<div id="bContent"></div>

Set your desired CSS opacity and other properties for the background and use the z-index property (z-index) to style and position the bContent div. With this you can place the div overtope of the background div without having it's opacity mucked with.


Another option is to RGBa. This will allow you to nest your divs and still achieve div specific opacity.


The last option is to simply make a semi transparent .png image of the color you want in your desired image editor of choice, set the background-image property to the URL of the image and then you won't have to worry about mucking about with the CSS and losing the capability and organization of a nested div structure.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jshbrmn
  • 1,737
  • 3
  • 22
  • 52
4

Just make sure to put width and height for the foreground the same with the background, or try to have top, bottom, left and right properties.

<style>
    .foreground, .background {
        position: absolute;
    }
    .foreground {
        z-index: 1;
    }
    .background {
        background-image: url(your/image/here.jpg);
        opacity: 0.4;
    }
</style>

<div class="foreground"></div>
<div class="background"></div>
  • Dedicated background element with opacity controller seems like the way to go. It'd be nice to have a real background opacity rule though. – Llama D'Attore May 20 '23 at 00:32