Question
How can I make an element's background image appear at 40% opacity while keeping the text inside it fully opaque?
For example, I expected the nested text to remain fully visible in this code, but both the background and text appear faded:
<div style="opacity: 0.4; background-image: url(...);">
<div style="opacity: 1;">
Text
</div>
</div>
Why does this happen, and what CSS approach should I use instead?
Short Answer
You will learn that the CSS opacity property applies to an element after it and all of its children have been drawn. Because of this, a child cannot restore its own opacity when a parent is transparent. You will also learn reliable ways to make only a background color or background image translucent.
Concept
The CSS opacity property controls the transparency of the entire rendered element. That includes:
- Its background color and background image
- Its text
- Its borders and shadows
- Every child element inside it
For example:
.card {
opacity: 0.4;
}
The browser first paints .card and everything inside it. It then blends that finished result with whatever is behind it at 40% opacity. Therefore, setting a child to opacity: 1 cannot undo the parent opacity.
.card {
opacity: 0.4;
}
.card p {
opacity: 1; /* Still appears faded because the parent is blended afterward. */
}
To keep content opaque, do not apply opacity to the container that holds the content. Instead, make a separate background layer transparent. The best technique depends on whether the background is a solid color or an image.
This matters in real interfaces such as hero banners, image cards, notification panels, and modal overlays, where readable text must appear above a softened or darkened background.
Mental Model
Think of a parent element with opacity as a finished poster covered by a transparent sheet.
- The browser prints the background, text, and child elements onto the poster.
- It places one semi-transparent sheet over the whole poster.
Adding opacity: 1 to the text is like printing darker text before the transparent sheet is placed on top. The sheet still affects it.
To fade only the background, use two layers instead:
- A transparent background layer behind
- A normal content layer in front
The content layer is never covered by the transparent layer, so it stays fully visible.
Syntax and Examples
For a solid background color, use an alpha color rather than the opacity property.
.notice {
background-color: rgb(20 80 160 / 40%);
color: white;
padding: 1rem;
}
The / 40% part is the alpha channel. It makes only the blue background transparent. The color property remains fully opaque.
You can also use rgba():
.notice {
background-color: rgba(20, 80, 160, 0.4);
color: white;
}
For a background image, place a translucent overlay in front of the image but behind the content:
<section class="hero">
<div class="hero__content">
<h1>Welcome</h1>
<p>This text remains fully opaque.</p>
</div>
</section>
.hero {
min-height: 240px;
padding: 2rem;
background-image:
linear-gradient(rgb(0 0 0 / 40%), rgb(0 0 0 / 40%)),
url("banner.jpg");
background-position: center;
background-size: cover;
color: white;
}
The first background in the list is painted on top. Here, the semi-transparent black gradient darkens the image, while the text is regular opaque content above both backgrounds.
Step by Step Execution
Consider this CSS:
.panel {
opacity: 0.4;
background: navy;
}
.panel p {
opacity: 1;
color: white;
}
And this HTML:
<div class="panel">
<p>Status: ready</p>
</div>
The browser processes the result conceptually as follows:
- It paints the navy background for
.panel. - It paints the white paragraph text inside
.panel. - The paragraph's
opacity: 1means the paragraph itself is painted normally at this stage. - The browser combines the parent and its child into one rendered result.
- It applies
.panel { opacity: 0.4 }to that entire result. - Both the navy background and white text are blended at 40% opacity.
Now compare it with an alpha background:
.panel {
background: rgb(0 0 128 / 40%);
}
.panel p {
color: white;
}
In this version, only the background color has 40% alpha. The paragraph is drawn normally and is not faded.
Real World Use Cases
- Hero sections: Darken a photograph so white headings and buttons are readable.
- Image cards: Add a translucent color wash over a product or article image while preserving crisp labels.
- Alerts and status panels: Use a lightly transparent success, warning, or error background without making the message hard to read.
- Modal backdrops: Use
opacityon a dedicated backdrop element, not on the modal dialog containing forms and buttons. - Video captions: Place captions above a semi-transparent overlay or gradient to improve contrast.
- Watermark-style decoration: Fade a separate decorative image layer without fading interactive content.
Real Codebase Usage
In production CSS, developers usually separate decoration from content.
Use alpha colors for color-only backgrounds
.toast--success {
background-color: rgb(22 163 74 / 15%);
border: 1px solid rgb(22 163 74 / 40%);
color: rgb(20 83 45);
}
This keeps text, icons, and controls fully visible.
Use a layered background for images
.article-header {
background-image:
linear-gradient(to bottom, rgb(0 0 0 / 15%), rgb(0 0 0 / 70%)),
url("/images/mountains.jpg");
background-size: cover;
background-position: center;
}
A stronger gradient near the bottom can make a heading readable without hiding the whole image.
Use a pseudo-element for reusable overlay layers
.banner {
position: relative;
isolation: isolate;
overflow: hidden;
color: white;
}
.banner::before {
content: "";
position: absolute;
inset: 0;
z-index: -1;
background:
linear-gradient(rgb(0 0 0 / 45%), rgb(0 0 0 / 45%)),
url("banner.jpg") center / cover;
}
The pseudo-element owns the visual background. The banner's actual content remains a separate, opaque layer.
For accessibility, developers also check that text has sufficient contrast against the final image and overlay combination.
Common Mistakes
Trying to override a parent's opacity in a child
.parent {
opacity: 0.4;
}
.child {
opacity: 1;
}
This does not work. Parent opacity is applied after the child is rendered. Move the opacity to a separate background or overlay layer instead.
Applying opacity to a card containing controls
.card {
opacity: 0.7;
background: white;
}
This also fades buttons, text, icons, and focus indicators. Use an alpha background color instead:
.card {
background: rgb(255 255 255 / 70%);
}
Using a transparent overlay above the text
An overlay can accidentally cover content or intercept clicks.
.overlay {
position: absolute;
inset: 0;
}
If it sits above buttons, it may block pointer interaction. Put content above it using z-index, or use a layered background-image when possible.
.content {
position: relative;
z-index: 1;
}
.overlay {
pointer-events: none;
}
Forgetting positioning for absolute overlays
An absolutely positioned pseudo-element needs a positioned ancestor:
.card {
position: relative;
}
Without it, the overlay may be positioned relative to an unexpected ancestor.
Assuming opacity changes only a background image
opacity has no "background only" mode. It always affects the rendered element as a whole.
Comparisons
| Technique | What becomes transparent? | Best use |
|---|---|---|
opacity: 0.4 | The element, its text, and all descendants | Fading an entire standalone item, such as a disabled decorative preview |
background: rgb(0 0 0 / 40%) | Only the background color | Transparent panels, alerts, and colored surfaces |
background-image: linear-gradient(...), url(...) | An image overlay layer | Hero images, banners, and image cards |
::before pseudo-element overlay | A separate generated layer | Complex reusable overlays and effects |
opacity is appropriate when everything should fade together. Alpha colors and separate layers are appropriate when content must remain readable and interactive.
Cheat Sheet
/* Fades everything: background, text, children, borders, and shadows */
.element {
opacity: 0.4;
}
/* Fades only a solid background color */
.element {
background-color: rgb(0 0 0 / 40%);
}
/* Adds a translucent overlay above a background image */
.element {
background-image:
linear-gradient(rgb(0 0 0 / 40%), rgb(0 0 0 / 40%)),
url("image.jpg");
background-size: cover;
}
Rules to remember:
opacityaccepts values from0to1.opacity: 0makes an element invisible, but it can still occupy layout space.- A child cannot cancel or exceed a parent's opacity.
- Use
rgb(... / alpha)orrgba(...)when only a background color should be transparent. - The first listed CSS background image is drawn on top of later backgrounds.
FAQ
Why does opacity: 1 on my child not work?
The parent is composited at its opacity after its children are painted. The child cannot reverse that final blending step.
How do I make only a CSS background color transparent?
Use an alpha color, such as background-color: rgb(0 0 0 / 40%) or background-color: rgba(0, 0, 0, 0.4).
How do I add opacity to a background image but not text?
Use a semi-transparent gradient as the first layer in background-image, followed by the image URL. Alternatively, use a pseudo-element overlay behind the content.
Is rgba() still valid CSS?
Yes. rgba() is valid and widely used. Modern CSS also supports the convenient rgb(red green blue / alpha) syntax.
Should I use opacity for disabled buttons?
Sometimes, but be careful. It fades all content and may reduce contrast too much. Also use the actual disabled attribute for native buttons or appropriate accessibility behavior for custom controls.
Can a pseudo-element overlay block clicks?
Yes, if it is above interactive content. Put the content above the overlay with stacking order, or add pointer-events: none to the overlay.
Which overlay color should I use for white text on a photo?
A semi-transparent black overlay is common because it darkens light areas. Test the final result because image contrast changes across the photo.
Mini Project
Description
Build a small promotional banner with a background photograph, a dark transparent overlay, a heading, descriptive text, and a button. The project demonstrates how to make an image less visually busy without fading the foreground content.
Goal
Create a readable image banner where the background is darkened at 45% opacity while the text and button remain fully opaque.
Requirements
Use a background image on the banner. Add a semi-transparent dark layer over the image. Keep the heading, paragraph, and button fully opaque. Make the image cover the banner area. Use semantic HTML elements.
Keep learning
Related questions
Add a Favicon to a Static HTML Page
Learn how to add a favicon to static HTML pages, use correct paths and icon formats, and troubleshoot browser caching and local-file issues.
Allow Only Numeric Input (0-9) in HTML Input Using jQuery
Learn how to allow only digits 0-9 in an HTML input using jQuery, with examples, validation tips, common mistakes, and best practices.
Apply CSS !important with jQuery .css()
Learn why jQuery .css() cannot set !important and how to use CSSStyleDeclaration.setProperty() to apply inline important styles safely.