One of the posts on this website that consistently gets a significant amount of traffic (5000+ page views this month alone) is a ridiculous article I wrote that discusses how to make a child element not inherit the opacity setting of its parent.
Basically, if a parent element has an opacity value set at, say, 0.5, all of its children will inherit that opacity setting, and there’s no way to reverse that opacity on the child elements.
That post I wrote discussed a hacky workaround where you actually remove the element from its parent, position it absolutely, then move it so it still appears in the same place it did when it was a child.
If you know anything about CSS positioning, then you know why this is not a great solution.
So I decided to write a script that fixes this issue. But first, let’s settle a few things.
The Best Way to Resolve This Issue
I’m guessing that in more than 90% of cases, this is pretty much a non-issue. If you need transparency on a parent element, you can do it using a few different methods that avoid this parent-child opacity issue:
- If it’s only a background color on the parent, use RGBA or HSLA
- If it’s a background image, use a transparent PNG
- If you’re just desiring a “washed out” look for a color or background image or pattern, do it in your image editor, or sample the washed-out color you want and insert it with Hex or RGB in your CSS
But hey, it’s fun to write polyfills and workarounds for these types of problems, and it does seem like this sort of thing is in demand, even if most developers are approaching the problem in the wrong way to begin with.
I realized that the workaround to get the child elements out of their parent and repositioned is not that crazy. So I wrote a script that does this exact thing automatically, but it’s much more effective than that original solution.
Here’s an embedded pen demonstrating thatsNotYoChild.js in action:
Go ahead, change the markup to anything you want inside the
#parent element; it should work for anything you put in there.
You can view the code in the embedded CodePen, and here’s a step by step description of what it does:
- Grab all child elements of the element that has the opacity setting, wrap them in a
- Use cloneNode to clone the newly-wrapped child group
- Place the new clone outside the parent element
- Change the ID of the original group
- Set the opacity of the original group to 0 (you can reduce the opacity of the children but you can’t raise it)
- Use getBoundingRect() (which works everywhere that’s relevant) to find the exact position and width of the original child group
- Use element.style to absolutely position and size the clone group using the values obtained from
- Use window.onresize to run the previous two steps every time the window is resized.
Compared to the old article I wrote that fixed this issue with a CSS-only solution, this solution has a few advantages. First, although the child elements are absolutely positioned, taking them out of the normal flow, the space the child elements occupy is still occupied by the original child group, which isn’t visible due to having its opacity set to 0. The cloned group overlays the same space, making it appear as if it never moves, and the other elements on the page don’t reposition themselves since they are subject to the positioning of the original, now invisible, child group.
The other advantage is that this solution doesn’t require any changes to the markup, whereas that other CSS-only solution required that you change the markup.
To use the script, just call the function like this, passing in the ID of the parent element that has opacity set:
I don’t know too much about the different DOM methods I used in this script. I’m guessing for example that
window.onresize is not great for performance and repaints.
This was, more or less, a fun little hacky script that’s not too heavy so maybe someone will find it useful, assuming there are no major performance issues with it.
If you have any feedback on improvements to the code, or see any potential bugs or drawbacks, feel free to comment and/or fork it.