112

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?

2
  • stackoverflow.com/questions/6624457/… 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. ( jsfiddle.net/4tTNZ ) Commented Aug 30, 2011 at 9:53
  • This answer is much more succinct and I believe is exactly the same. Commented Apr 19, 2014 at 20:15

9 Answers 9

212

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"); 
Sign up to request clarification or add additional context in comments.

9 Comments

@jj_: Because at the time there was very limited support for linear-gradient. The accepted answer I wrote is over 4 years old ;)
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 ;)
@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.
I think we can agree that it achieves the intent of the question so yeah it's a valid answer for the question.
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.
|
126

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:

8 Comments

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. jsfiddle.net/sbGb4/2
I thought there is a css3 trick for it that I am missing - but this is great too!
@Lollero good point! z-index is a pain, but this should be relatively safe as long as you give the parent a positive index.
@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.. css-tricks.com/2151-rgba-browser-support
@Alon I added another method using the ::before pseudo-element. Was this the one you were looking for?
|
9

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> 

Comments

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/

1 Comment

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.
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> 

Comments

0

The approach of using an inner absolute element with 100% width and height didn't work for me due to how the layout changed and the how impractical it was to keep track.

So I came up with a solution; rendering the image to a canvas with a set alpha, and then getting a blob URL from the canvas.

async function generateDataUrlFromImage(src: string, opacity: number) { return new Promise(async (resolve) => { const img = document.createElement('img'); img.src = src; await img.decode(); const canvas = document.createElement('canvas'); canvas.width = img.naturalWidth; canvas.height = img.naturalHeight; const ctx = canvas.getContext('2d')!; ctx.globalAlpha = opacity / 100; ctx.drawImage(img, 0, 0); canvas.toBlob((blob) => { resolve(URL.createObjectURL(blob!)); }); }); } 

Not the most efficient, but it's foolproof in terms of layout since you can really use background-image. It might not be performant enough for other images, the image that I needed to use was a small 150x150px pattern so it's good enough; I benched it at about 20ms.

Comments

-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

Comments

-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...

Comments

-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%)

1 Comment

what has this to do with opacity?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.