Non-Transparent Elements Inside Transparent Elements

Avatar of Chris Coyier
Chris Coyier on (Updated on )

Update in 2018: While we still don’t have something like background-opacity, we do now have rgba() and hsla() which would be the easy solution for solid colors like in this article.

Reader Shane left a comment:

If using transparency on a block element it makes the text inside transparent as well. Is there a way I can prevent that from happening? I tried putting the text in another div and setting the opacity to 100%, but that didn’t do the job. Although, logically, I thought it would!


Logically, that makes sense to me to. Is that how it works in practice? Of course not. This is, in my opinion, a major failing of CSS. People just expect that this is possible. It’s a very common effect in print design. Unfortunately, it’s just not so easy on the web. Here is one way out of this mess.

First, you create a bar making sure to use the CSS settings for all browsers. Here is the bar:

<div class="bar">
  <h2>Some mild-mannered text trapped inside a bar.</h2>

And this is how you style it:

.bar {
  height: 4em;
  padding-top: 2em;
  opacity: 0.5;
  background: black;
  border-top: 3px solid #ccc;
  border-bottom: 3px solid #ccc;
  margin-top: 5.0em;

This is where you notice that the text inside the bar as taken on the transparency of the bar itself. You don’t want that, it’s making the text hard to read! So you get smart and apply 100% transparency to the text inside the div. Doesn’t work right?

You’ll have to resort to some trickery.

As far as I know, there is just no way to force those child elements to be an less transparent than their parent element. And therein lies the solution. What if that child element wasn’t technically a child element.

As you likely know, just because an element occupies the same space as another element, doesn’t make one a child of the other. That’s the beauty of CSS positioning. So the trick to getting our non-transparent text into a transparent div is just to put that text outside of the div and push it visually inside with some CSS positioning.

Here is how we’ll do it:

<h2 class="ontop">Haha! I'm free of my transparent prison.</h2>
<div class="bar"></div>

Notice the class applied to the text. Now you’re going to have to do whatever you need to do with CSS positioning to get it where it needs to be. Negative margins are a popular way to do this. Here I just set the top position:

h2.ontop {
  position: relative;
  top: 4.7em;

View Demo