If you've ever wondered how to get a semi-transparent background box behind text using CSS without also making the text semi-transparent (and without resorting to absolute positioning or background images), wonder no more! I've figured out a neat CSS trick to make this effect possible.
Today's installment of 'CSS Guru' is brought to you by the letter C, the letter S, another letter S, and the numbers #000; with special guest stars filter,-moz-opacity, and opacity.
Show all blog entries
While I was working on the redesign for The Unincorporated Man last week I invented a nice CSS effect that I'd wondered about before but never had to figure out. The background is fairly dark, and I wanted hovering semi-opaque boxes above it containing light-colored text. Unfortunately, part of the background is also very light so I wanted this box dark, but when you add opacity to a div layer it applies the effect to everything in that layer. Normally you'd set up an absolutely positioned box with some opacity on it, and then lay another div box on top and make sure the height and width match. But I need my text fully opaque, and the boxes couldn't have a predefined size, and I didn't want to use an image for the background of this darker box. How to accomplish this?
The trick is in using z-index and a container div. The outside container defines any borders for the box, and inside the box are two sibling div layers, one with a lower z-index that has the background color and opacity, and another with a higher z-index containing the text.
The outer container has position: relative, the width, and whatever placement on the page you want, float, absolute, anything. it just needs position set so the inner div layers' positions are relative to it.
"What the hell are you talking about?" you say. Good question. Allow me to digress.
When you give a div layer a position (either absolute or relative), it takes it's position cues from the first parent it finds that has a position defined. So a div layer with absolute positioning inside a div layer without position will be absolutely positioned to the body of the document. If you give the outer div layer a position, then the inner div layer will be absolutely positioned inside the outer div layer.
For example, let's say you have a div that is centered on your page without position defined. Inside that is a div with absolute position top: 0 and left: 0. This inner div will appear in the upper left corner of the page. But if you give the outer div a position: relative, then the inner div layer will appear in the upper left corner of that div.
OK? Can we move on?
Here's the opacity trick: You have your outer div with relative position, and two inner divs. The outer div css looks like this: style="border: 1px solid green; overflow: hidden;". The overflow is the key to this trick. One of the inner divs is absolute positioned and has a background color of solid black and opacity of 35, a z-index of 1 and a height and width of 100%. This positions the div in the upper-left corner and it extends beyond the left and right sides of the outer div though you can't see that because the outer div has its overflow hidden.
Then you have a div with the text in it. This text div has the padding for the box, and all the content. This div, since it is relatively positioned, will sit in the upper-left corner of the box, and the z-index will ensure placement above the background div layer.
Because this second content div is relatively positioned it will determine the size of the outer div; the outer div will grow with it, revealing more of the semi-transparent background as it does.
Here's the entire code block:
<div id="outerDiv" style="position: relative; border: 1px solid green; width: 500px;">
<div id="semiTransparentDiv" style="position: absolute; background-color: black; filter:alpha(opacity=35);-moz-opacity:.35;opacity:.35; height: 100%; width: 100%; z-index: 1;"></div>
<div id="contentDiv" style="position: relative; z-index: 2; padding: 10px; color: white; font-weight: bold;">here's where the text goes. Height is determined by this text. As this content box grows, so does the outer div layer. This content is not semi-transparent, or you would barely be able to read this text.</div>
</div>
Check it out in action here.



