You can't change the opacity of a background image without affecting the opacity of the whole object, but the workaround is simpler than you think!
If you're trying to make text or a child object stand out by fading the background, also reducing the opacity of the foreground content probably defeats the point of changing the opacity in the first place, but we can get around this using the ::before
pseudo-element.
This is because ::before
is a child of the main element, which means we can target it independently of our other child elements. Imagine you want to set the opacity of the image below:
Before styling ::before
<div id='parent'>
<div id='child'>
<strong>Good doggo</strong>
</div>
</div>
body {margin:0;}
#parent {
background-image: url('https://images.unsplash.com/photo-1546527868-ccb7ee7dfa6a');
background-size:cover;
position: relative;
height: 100vh;
}
#child { /* #child CSS is purely for styling */
font-family: sans-serif;
font-size: 60px;
color: purple;
text-align: center;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
If you set the opacity of #parent
, e.g. opacity: 0.6;
you'll end up with faded text as well as the background. The doggo may be good, but the caption is bad.
After using ::before
To fix this, we can add a ::before
pseudo-element and move the background-image, background-size & opacity to it.
We'll also need to absolutely position it and set top, bottom, left & right to 0 so it exactly overlaps the parent, and also set content: ""
to force the pseudo-element to display.
body {margin:0;}
#parent::before {
background-image: url('https://images.unsplash.com/photo-1546527868-ccb7ee7dfa6a');
background-size: cover;
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
opacity: 0.6;
content: "";
}
#parent {
position: relative;
height: 100vh;
}
#child { /* #child CSS is purely for styling */
font-family: sans-serif;
font-size: 60px;
color: purple;
text-align: center;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
Shifting this CSS around leaves us with a much more visible title (albeit at the expense of the very patient, good doggo):