106

Let's say I have

<div class="myDiv">Hi there</div>

I want to put a background-image and give it an opacity of 0.5 – but I want that the text I have written will have full opacity (1).

If I would write the CSS like this

.myDiv { opacity:0.5 }

everything will be in low opacity – and I don't want that.

So my question is – How can I get low-opacity background image with full opacity text?

Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
Alon
  • 7,618
  • 18
  • 61
  • 99
  • http://stackoverflow.com/questions/6624457/how-to-set-opacity-to-the-background-color-of-a-div/6624569#comment-7823841 Note that i do have comment there ( under Phil's answer ) showing a way to do it with css opacity, if that is the preferred way. ( http://www.jsfiddle.net/4tTNZ ) – Joonas Aug 30 '11 at 09:53
  • This [answer](http://stackoverflow.com/a/4183985/464273) is much more succinct and I believe is exactly the same. – JohnAllen Apr 19 '14 at 20:15

8 Answers8

199

So here is an other way:

background-image: linear-gradient(rgba(255,255,255,0.5), rgba(255,255,255,0.5)), url("your_image.png");
Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
GrmXque
  • 1,999
  • 1
  • 10
  • 2
  • 4
    @jj_: Because at the time there was very limited support for `linear-gradient`. The accepted answer I wrote is over 4 years old ;) – mekwall Dec 16 '15 at 10:31
  • 3
    Maybe you could add a comment or a little update to your question, informing that this is now the new good way to do it. See you in 4 years for a new update ;) – Redoman Dec 17 '15 at 11:48
  • @jj_: Actually, this solution doesn't make the image transparent. It only adds a white layer with 50% transparency on top of it. Hence, it's not a valid answer for the question. – mekwall Jan 26 '16 at 14:38
  • 11
    I think we can agree that it achieves the intent of the question so yeah it's a valid answer for the question. – David Clarke Feb 10 '16 at 08:49
  • This is by far the most creative, intuitive way to solve this problem. It is also a LOT easier to use than the alternatives and provides you with more control. By allowing it to be a gradient you can make the area at the bottom lighter so the footers can be read more easily. – Brad Apr 14 '17 at 18:18
  • Not "pure" opacity in the sense, but yeah this is the best answer. So clean and simple. The accepted answer is too outdated and clumsy for 2018. – Andy B Jan 22 '18 at 17:37
  • Sadly, this will not work if you need to support IE9 – fnagel Apr 06 '18 at 14:46
  • This solution still affects any text that is a child of the background image. –  Oct 01 '19 at 00:07
  • This is working on most cases. But if you have divs staked on top of each other, with let's say a 0.5 opacity you will see a white (ish) background instead of seeing the other background. White with transparency is not pure opacity. I'm still waiting for this to be solved in css for some time now. – Mareș Ștefan Nov 03 '22 at 21:25
124

Nope, this cannot be done since opacity affects the whole element including its content and there's no way to alter this behavior. You can work around this with the two following methods.

Secondary div

Add another div element to the container to hold the background. This is the most cross-browser friendly method and will work even on IE6.

HTML

<div class="myDiv">
    <div class="bg"></div>
    Hi there
</div>

CSS

.myDiv {
    position: relative;
    z-index: 1;
}

.myDiv .bg {
    position: absolute;
    z-index: -1;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background: url(test.jpg) center center;
    opacity: .4;
    width: 100%;
    height: 100%;
}

See test case on jsFiddle

:before and ::before pseudo-element

Another trick is to use the CSS 2.1 :before or CSS 3 ::before pseudo-elements. :before pseudo-element is supported in IE from version 8, while the ::before pseudo-element is not supported at all. This will hopefully be rectified in version 10.

HTML

<div class="myDiv">
    Hi there
</div>

CSS

.myDiv {
    position: relative;
    z-index: 1;
}

.myDiv:before {
    content: "";
    position: absolute;
    z-index: -1;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background: url(test.jpg) center center;
    opacity: .4;
}

Additional notes

Due to the behavior of z-index you will have to set a z-index for the container as well as a negative z-index for the background image.

Test cases

See test case on jsFiddle:

mekwall
  • 28,614
  • 6
  • 75
  • 77
  • 2
    I'm super paranoid when it comes to using negative values with z-index.. but, i cant argue with results. Howevveer, i would add `width: 100%; height: 100%;` to the `.bg` so that ie6 can spread the bg inside the parent div. http://jsfiddle.net/sbGb4/2/ – Joonas Aug 30 '11 at 10:20
  • I thought there is a css3 trick for it that I am missing - but this is great too! – Alon Aug 30 '11 at 11:07
  • @Lollero good point! `z-index` is a pain, but this should be relatively safe as long as you give the parent a positive index. – mekwall Aug 30 '11 at 12:22
  • @Alon if you check that comment I wrote under your Question post. I have link there to another question that has several other options Including rgba Which is the css3 option. Heres quite good trick for older ie.. http://css-tricks.com/2151-rgba-browser-support/ – Joonas Aug 30 '11 at 12:33
  • @Alon I added another method using the `::before` pseudo-element. Was this the one you were looking for? – mekwall Aug 30 '11 at 12:35
  • I got this to work completely without the `z-index` or the `:before`. See answer below. – abalter May 12 '17 at 16:40
  • @abalter You only omitted z-index. Your answer uses the "Secondary div" method that is listed first in my answer. Trusting the browser to handle z-index (as expected) is usually not a good idea. – mekwall May 29 '17 at 09:39
  • Finally, this is it. THANKS @mekwall – Dženis H. Aug 17 '19 at 02:51
8

css

div { 
    width: 200px;
    height: 200px;
    display: block;
    position: relative;
}

div::after {
    content: "";
    background: url(image.jpg); 
    opacity: 0.5;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    position: absolute;
    z-index: -1;
}

html

<div> put your div content</div>
Harsukh Makwana
  • 4,296
  • 3
  • 27
  • 34
0

I implemented Marcus Ekwall's solution but was able to remove a few things to make it simpler and it still works. Maybe 2017 version of html/css?

html:

<div id="content">
  <div id='bg'></div>
  <h2>What is Lorem Ipsum?</h2>
  <p><strong>Lorem Ipsum</strong> is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen
    book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with
    desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
</div>

css:

#content {
  text-align: left;
  width: 75%;
  margin: auto;
  position: relative;
}

#bg {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: url('https://static.pexels.com/photos/6644/sea-water-ocean-waves.jpg') center center;
  opacity: .4;
  width: 100%;
  height: 100%;
}

https://jsfiddle.net/abalter/3te9fjL5/

Community
  • 1
  • 1
abalter
  • 9,663
  • 17
  • 90
  • 145
  • 1
    This is doing the same as the "Secondary div" in my answer, with the only difference being that you omitted the z-index (it is possible this behaves differently today and may also depend on browser). But trusting the browser to behave as expected is usually a bad idea. – mekwall May 29 '17 at 09:37
0

Hello to everybody I did this and it worked well

 var canvas, ctx;

  function init() {
   canvas = document.getElementById('color');
   ctx = canvas.getContext('2d');

   ctx.save();
   ctx.fillStyle = '#bfbfbf'; //  #00843D   // 118846
   ctx.fillRect(0, 0, 490, 490);
   ctx.restore();
  }
section{
  height: 400px;
  background: url(https://images.pexels.com/photos/265087/pexels-photo-265087.jpeg?w=1260&h=750&auto=compress&cs=tinysrgb);
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  position: relative;
 
}

canvas {
 width: 100%;
 height: 400px;
 opacity: 0.9;

}

#text {
 position: absolute;
 top: 10%;
 left: 0;
 width: 100%;
 text-align: center;
}


.middle{
 text-align: center;
 
}

section small{
 background-color: #262626;
 padding: 12px;
 color: whitesmoke;
  letter-spacing: 1.5px;

}

section i{
  color: white;
  background-color: grey;
}

section h1{
  opacity: 0.8;
}
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Metrics</title>
 <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">  
</head>  
  
<body onload="init();">
<section>
<canvas id="color"></canvas>

<div class="w3-container middle" id="text">
<i class="material-icons w3-highway-blue" style="font-size:60px;">assessment</i>
<h1>Medimos las acciones de tus ventas y disenamos en la WEB tu Marca.</h1>
<small>Metrics &amp; WEB</small>
</div>
</section> 
adragom
  • 1
  • 1
-1

This can be done by using the different div class for the text Hi There...

<div class="myDiv">
    <div class="bg">
   <p> Hi there</p>
</div>
</div>

Now you can apply the styles to the

tag. otherwise for bg class. I am sure it works fine

-1

None of the solutions worked for me. If everything else fails, get the picture to Photoshop and apply some effect. 5 minutes versus so much time on this...

user2060451
  • 2,576
  • 3
  • 24
  • 31
-1
<!DOCTYPE html>
<html>
<head></head>
<body>
<div style=" background-color: #00000088"> Hi there </div>
<!-- #00 would be r, 00 would be g, 00 would be b, 88 would be a. -->
</body>
</html>

including 4 sets of numbers would make it rgba, not cmyk, but either way would work (rgba= 00000088, cmyk= 0%, 0%, 0%, 50%)

villager1
  • 80
  • 1
  • 10