DEV Community

Jessica Chan
Jessica Chan

Posted on • Originally published at coder-coder.com

How to change background image opacity in CSS

When building a website, you may often want to put a background image on an HTML <div> that also contains text or other content.

And to make the text stand out, you want to change the opacity of that background image in CSS so that it’s semi-transparent. But you’ve tried, and you can’t change the opacity of the background image without also affecting the text or other child elements!

What can you do? Not to worry– this article will give you some practical solutions to controlling your background image opacity.

So, first, the bad news…

There’s no CSS property that you can use to change the opacity of only the background image.

Unlike background colors, which allow you to adjust the alpha channel to control opacity, it simply doesn’t exist for the background-image property. Maybe someday?

In the meantime, let’s take a look at just why changing the opacity will affect text or other content in that element. Then we’ll go over workarounds you can use.

Opacity changes on a parent will get inherited to child elements.

For example, let’s say you have a div element with some text inside, and you have set the background-image on the parent .hero element.

    <div class="hero">
        <h1>Cute kittehs everywhere!</h1>
    </div>

Then you adjust the opacity of the parent to try to make the background image semi-transparent, like this:

    .hero {
        background-image: url('https://placekitten.com/1200/800');
        opacity: 0.75;
    }

Opacity is automatically inherited by child elements, so when you adjust the opacity of the parent element, it will affect all child elements in that parent layer. (This is similar to how z-index is also inherited.)

So you will end up with all the elements, both background image and text, having that reduced opacity.

Alt Text

Definitely not what we want to see!

Solution: Put the background image into a pseudo-element of the parent.

To fix this issue, we need to put the background image into a child element of the parent. This will ensure that the background image and the text content will be on their own “layer” in the parent. You can then control each layer’s opacity without affecting each other!

One approach you can use is to put the background-image styles in a pseudo-element of the parent element.

    .hero {
        position: relative; 
        height: 100vh;
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    .hero::before {    
          content: "";
          background-image: url('https://placekitten.com/1200/800');
          background-size: cover;
          position: absolute;
          top: 0px;
          right: 0px;
          bottom: 0px;
          left: 0px;
          opacity: 0.75;
    }

    h1 {
      position: relative;
      color: #ffffff;  
      font-size: 14rem;
      line-height: 0.9;
      text-align: center;
    }

Since the pseudo-element is a sort of child of the parent, you can change the opacity of it without affecting the text content.

To make that pseudo-element the same size as the parent, you’ll have to absolutely position it and set its top, right, bottom, and left values to zero so it doesn’t collapse. Also, as a pseudo-element, it needs to have the content property set, otherwise it won’t show up on the page.

(You can also put the background image into its own child element, but using a pseudo-element helps keep the HTML simplified.)

Then for the text, which we have in the <h1> tag, you will need to set it to position: relative so that it will be on top of the pseudo-element and background image. If you don’t explicitly set the position property, it will be hidden underneath the absolutely positioned pseudo-element in the z-index layer stack.

Lastly, don’t forget to set the parent to position: relative to keep the child within bounds!

Now, the text will still be at a default opacity of 1, and the reduced opacity setting will be limited to the background image in the pseudo-element.

Alt Text

I have the code for the above example in a Codepen— feel free to play around with it!

Alternative solution: add an overlay with reduced opacity and background-color on top of the background image.

Another solution is instead of changing the opacity of the background image, you add an overlay with a semi-transparent background color on top of the background image.

The HTML markup will be the same as the previous solution. In the CSS, you can set the background-image directly in the parent element, with no opacity change.

The pseudo-element of the parent will then contain the semi-transparent background-color.

This is accomplished by setting the background-color property using the rgba() syntax, where the first three characters are the RGB color numbers, and the last number is the alpha or transparency setting. We’re using 0,0,0 for the RGB color, which translates to black.

An alpha value can range from 0 (0% opacity) to 1 (100% opacity). So our value of 0.25will result in an overlay of 25% opacity.

Here’s what that will look like in the code:

    .hero { 
        position: relative; 
        height: 100vh;
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
        background-image: url('https://placekitten.com/1200/800');
        background-size: cover;
    }

    .hero::before {
        content: "";
        position: absolute;
        top: 0px;
        right: 0px;
        bottom: 0px;
        left: 0px;
        background-color: rgba(0,0,0,0.25);
    }

The result will look like this:

Alt Text

And here’s the Codepen for this overlay solution!

Both solutions have a very similar-looking result. The first solution has a background image set at 75% opacity. And the second solution adds a black overlay at 25% opacity. So they’re not quite the same, but they are similar.

The overlay solution is also handy if you want to add a toned color to the background image. Here’s what that would look like if we set the overlay background-color to rgba(152, 66, 211, 0.63):

Alt Text

I hope this article helps explain how to successfully have text on a semi-transparent background image. Feel free to leave a comment below if you have a question or feedback!

Originally published on my blog, Coder-Coder.com.

Discussion (6)

Collapse
adityamitra profile image
Aditya Mitra

How will you change the background opacity of an image html element inside a div container only which also contains a header? The header should not be affected

Collapse
anguramshan profile image
Anguram Shan

you have two ways,

  • seperate with div elements
  • using css access the correct child element .i.e using n-th-child-element
Collapse
thecodercoder profile image
Jessica Chan Author

If it's an element, you can adjust the opacity of that without affecting other sibling elements

Collapse
adityamitra profile image
Aditya Mitra

You mean changing the opacity of the img element only without touching the header.
Yeah, that will work!

Thread Thread
thecodercoder profile image
Jessica Chan Author

oop yes, I typed in "img" with brackets so it got messed up 😂

Collapse
anguramshan profile image
Anguram Shan

Learning from your channel and your blog is so useful. Love you sooo much.

Keep🆙