CodeinWP CodeinWP

CSS Opacity That Doesn’t Affect Child Elements

Update (March 19, 2013): I’ve written a script called thatsNotYoChild.js that fixes this issue automatically to ensure you’re using CSS opacity that doesn’t affect child elements.

CSS Opacity That Doesn't Affect Child ElementsThis is a quick tip to demonstrate a way to work around the problem of child elements in your HTML inheriting the “alpha” settings of their parent. This tip is not necessarily recommended, because it creates extra markup and is a little bit messy. But I’m sure it could come in handy in a rare case, depending on the layout of the elements involved, the content, the type of site, etc.

First, here is the CSS code necessary to make an HTML element semi-transparent:

#alpha {
  background: url(bicycle.jpg) no-repeat 0 0;
  opacity: 0.3;
}

This works in all browers, and the last line ensures that the background image of the bicycle is shown “washed out” or with 30% opacity (or 70% transparency, if you’re a pessimist!).

The Problem With CSS Opacity

The problem occurs when we add child elements to the html element that this code affects. All child elements will inherit the same opacity settings, even if you try to specify full opacity for all those elements (which would be too troublesome to do anyhow).

The Hacky Solution

How can we work around this problem? In some instances, you could visually mimic a parent-child relationship between the elements using absolute positioning, and this will resolve the problem.

View Demo Comparing Two Examples

You’ll notice at the demo link above that the same set of visual elements is duplicated. The one on the left has the typical parent-child inheritance issue, so the blue background is shown washed out, at 30% opacity. But the example on the right looks exactly the way we want it to look — the opacity is set only on the element that has the bicycle background image.

You could add more elements to the section on the right, and none of them will inherit the transparency, because, technically, they are not children of the bicycle <div>. They are actually siblings of the bicycle <div>, but they are positioned absolutely so that visually they appear to be children.

Here is the section of code that styles the second example:

#alpha_wrapper {
  width: 540px;
  height: 360px;
  float: left;
  position: relative;
  color: #fff;
}

  #alpha_2 {
    background: transparent url(bicycle.jpg) no-repeat 0 0;
    width: 540px;
    height: 440px;
    float: left;
    opacity: 0.3;
  }

  #text_holder_2 {
    background: blue;
    position: absolute;
    top: 20px;
    left: 20px;
    width: 500px;
  }

The key is the fact that the bicycle element does not actually have any children, so it doesn’t affect anything else on the page. But, as with virtually any hack or workaround, there are drawbacks.

Definite Drawbacks

This method does qualify as a workaround that could be considered if you ever want to remove inherited opacity settings on child elements. But its drawbacks are probably convincing enough to prevent its use in most cases, so it’s important to mention them here.

  • Since the bicycle element does not actually contain any content, you have to specify a width and height, and alter the width and height every time you add more content to it. That in itself is probably enough reason to abandon this method in most situations.
  • Second, because the absolutely positioned element is not really a child of the bicycle element, maintenance of this section would be more difficult, especially if this is an inherited project.
  • Third, the absolutely positioned element is out of document flow, so this could cause layout issues in some circumstances if changes were made to the page or content.
  • Finally, it requires one extra <div>

27 Responses

  1. I agree this problem is a thing that definetly needs a workaround. But as you write, this should not be a recommended way to solve the problem. I would ideally recommend using jQuery/javascript soulutions instead of this fix, but at least you demonstrate it’s possible to make such a hack – which is great. The attributes -moz-opacity and -khtml-opacity should by the way not be necessary to make a element transparent and cross-browser compatible (see http://www.quirksmode.org/css/opacity.html). :-)

  2. tzcreative says:

    Another option, although not always ideal, is to use flash for the item that requires transparency adjustment and publish with a transparent background. As long as you publish in player 7, 99% of people can see it.

  3. Phil says:

    Nicely explained. I was hoping to see a 3rd option though! How about png opacity?

    p.s. your captcha refresh doesn’t work!

  4. Kent says:

    I think it’s tempting to use CSS for everything, but the fact is that in this current day – CSS just doesn’t do everything. Trying to make it do so causes more code and a loss of the page flow

    The BEST method for this is to use a small transparent PNG (make sure you install a PNG-hack script for those on IE6) and go that route. It will run fast and work like it’s supposed to.

  5. Dimox says:

    That is how I usually do. But, unfortunately, not always possible to use this method.

  6. @Phil:

    The captcha refresh seems to work fine for me. Can you describe exactly what went wrong and/or test it again? Thanks.

  7. brian says:

    When I saw this link on Twitter, I thought WOW – A SOLUTION!

    But so disappointed this was what I did many months back. :( Well, still hopes for more improvements on CSS opacity support.

  8. Daniel Apt says:

    @ Bård Øien

    I don’t think JavaScript is a good solution either, what happens if somebody disabled JavaScript? Then the user would get the same problem. I prefer the one used here, however I wouldn’t call it a hack. It’s normal CSS syntax and it isn’t using tricks

  9. Si says:

    This must be the most misleading post ever. The title asks a question your post does not answer, by moving the alphatised content behind the text it is no longer a child element.

    This is a relevant method to use alpha for backgrounds but it is often not possible as content is dynamic.

    I got excited for no reason : (

  10. @Si:

    It’s not misleading, because it gives a solution to the problem of children inheriting opacity. Just because the end result causes the elements to no longer, technically, be “children” doesn’t mean it’s not a viable solution to how to treat “child” elements.

    People use Javascript to manipulate the DOM all the time, but that doesn’t mean those solutions are invalid.

    I suppose I could have put the word “child” in quotes to be more technical about it. :o)

  11. Alex says:

    You’re example doesn’t work in ie6 (parallels)… the blue box and the text have disappeared on the right hand example.

    Which browsers were you testing in? ie6 is still being used by lots of people, if you are producing accessible web sites you still have to consider them.

    To any ie6 users who are reading this… it’s time to move on & get a different browser, save us developers a headache!

  12. @Alex:

    Thanks for the heads up on that. Generally, for tutorial stuff, I don’t do extensive testing in every browser. I just don’t have the time for that. But I usually do a quick check in the basic 3 (IE6, IE7, FF3).

    I’ve corrected it, and at the same time learned an interesting way to fix IE6 absolute positioning bugs: Add “clear: both” to the absolutely positioned element.

    Thanks again.

  13. chris says:

    The simplest and most reliable solution, it seems to me, is to employ a background image, such as a 1 x 1 pixel semi-transparent png or gif that repeats through the containing element. This allows for a dynamic (elastic) result based upon the changing dimensions of the content within the container.

  14. Kravimir says:

    I’ve used a similar technique before, but I gave “position:relative” to the element equivalent to “#text_holder_2” and “position:absolute” to the element equivalent to “#alpha_2” (and set z-index properties as needed) in order to avoid losing control of the document flow.

    Now though, I use a PNG and DD_belatedPNG for IE6 ( http://www.dillerdesign.com/experiment/DD_belatedPNG/ ).

  15. Mike says:

    @ Chris:

    Thanks, that was a really good idea and easy solution to my problem. The only issue is that IE6 doesn’t support transparent .pngs, but that’s a sacrifice.

  16. MikePriest says:

    IE 6 can support transparent PNG’s take a look with javascript:

    http://24ways.org/2007/supersleight-transparent-png-in-ie6

    jQuery version:

    http://jquery.andreaseberhard.de/pngFix/

    Hope this helps you out.

  17. shubham says:

    DUDE ITS NOT WORKING IN MOZZILA FIREFOX

    REPLY ME THE ECXACT THE SOLUTION FOR OPACITY BLOCKING

    HURRYYYYYYYYYYYYYYYYYYY

    M WAITING

    1. #alpha_wrapper {
    2. width: 540px;
    3. height: 360px;
    4. float: left;
    5. position: relative;
    6. color: #fff;
    7. }
    8.
    9. #alpha_2 {
    10. background: transparent url(bicycle.jpg) no-repeat 0 0;
    11. width: 540px;
    12. height: 440px;
    13. float: left;
    14. filter: alpha(opacity=30);
    15. -moz-opacity: 0.3;
    16. -khtml-opacity: 0.3;
    17. opacity: 0.3;
    18. }
    19.
    20. #text_holder_2 {
    21. background: blue;
    22. position: absolute;
    23. top: 20px;
    24. left: 20px;
    25. width: 500px;
    26. }

    • Make sure the element you want to avoid opacity is not a child element of the one that has opacity. That is, don’t wrap it in the child DIV. Place it outside the parent in your HTML, then the opacity will not affect it. You then have to reposition the child using absolute positioning, to make it look like a real child element.

  18. Ilya says:

    I agree with the sentiments that this is a less then desirable solution. I was looking for something that would replace jQuery but I guess this can be easily achieved with Javascript. Great comments.

  19. Behrang says:

    A better way is to use rgba (for example, rgba(0, 0, 0, 0.6)) rather than opacity. That way the child elements don’t inherit the opacity.

  20. nerdyprog says:

    Use rgba.;)
    e.g :

    background-color: rgba(255,255,255,1);/* >>> opacity = 1*/
    background-color: rgba(255,255,255,.6); /*>>> opacity = 0.6*/

    Piece of cake, isn’t it ? ;)

  21. AlexData says:

    How about if the DIV CHILD you’re trying to make non-opacity on, is inside a draggable, resizeable DIV PARENT…

    So i have a parent div that is made draggable/resizeable using JQUERY (google api)
    and inside that parent div there is a child div, that I want to be non-transparent,
    how to go about to make this happen?

    The JQUERY code i am reffering to is similar to this code here: http://www.innovativephp.com/crop-images-using-php-gd-library-and-jquery-resize/
    But im also adding a child element inside that resizeable area, because i need some text and images inside it…

    So how to go about that?

  22. Allan Sormani says:

    CSS Opacity That Doesn’t Affect Child Elements?

    This is not an accurate title for such solution. Your workaround it’s implementing a separated div/container to handle the background image with the opacity attribute applied at the same level as the item or container holding the text you are showing in your demo.

    It works but it adds unnecessary html tags to the DOM.

    I have another solution for this issue I will be posting soon, and does not use extra div/containers

  23. AR says:

    Thanks so much for your help with this.

  24. Hello all.

    I am Anietie James from Nigeria.

    The best way to get this done is by using a transparent png as the background. A 1 x 1 pixel semi-transparent png worked for me (gif didnt work)

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field and deep URLs are not allowed in the "Website" field. If you use keywords or deep URLs, your comment or URL will be removed. No foul language, please. Thank you for cooperating.

Markdown in use! Use `backticks` for inline code snippets and triple backticks at start and end for code blocks. You can also indent a code block four spaces. And no need to escape HTML, just type it correctly but make sure it's inside code delimeters (backticks or triple backticks).