How to change background image opacity in CSS
Tags: css
Published: 2020-03-22 17:55:32

---
title: How to change background image opacity in CSS
published: true
description: 
tags: css
canonical_url: https://coder-coder.com/background-image-opacity/
---
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](https://developer.mozilla.org/en-US/docs/Glossary/Alpha) 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.

```html
    <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:

```css
    .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](https://coder-coder.com/z-index-isnt-working/#4-the-element-is-in-a-lower-stacking-context-due-to-its-parents-z-index-level) is also inherited.)

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

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/u66as5eth3z75yb7nuj2.jpg)
<figcaption>Definitely not what we want to see!</figcaption>

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

```css
    .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](https://css-tricks.com/a-little-reminder-that-pseudo-elements-are-children-kinda/) 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](https://coder-coder.com/z-index-isnt-working/#2-the-element-doesnt-have-its-position-set).

Lastly, don’t forget to set the parent to `position: relative` to keep the child [within bounds](https://coder-coder.com/css-position-layout/#an-absolutely-positioned-element-needs-to-position-itself-in-relation-to-a-positioned-ancestor)!

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](https://dev-to-uploads.s3.amazonaws.com/i/9aeug0ockz4e2tqn5h2f.jpg)

I have the code for the above example in a [Codepen](https://codepen.io/thecodercoder/pen/xxGOyPe)— 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](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#RGB_colors), 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.25`will result in an overlay of 25% opacity.

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

```css
    .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](https://dev-to-uploads.s3.amazonaws.com/i/qnkb3xq9gi8ngym206r8.jpg)

And here’s the [Codepen](https://codepen.io/thecodercoder/pen/dyoXgQo) 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](https://dev-to-uploads.s3.amazonaws.com/i/8xxkdqz8rrhbftc2n01b.jpg)

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](https://coder-coder.com/background-image-opacity/).