Expanding on my previous comments, it seems that the responses have not fully addressed the main point of your question and your counter argument in the comments. Achieving what you are looking for with a parent and child relationship is impossible; instead, you would need siblings within the parent with varying opacities while keeping the parent's opacity unchanged.
An element with zero opacity essentially acts as an invisibility cloak, hiding everything it contains, including text nodes and other elements inside it. Using a <div>
will yield the same result as using a <span>
: the child element remains unseen because it is shielded by its opaque parent.
In your example from the comments, where you wrapped an <h1>
element within a <p>
element like this:
<p style="opacity: 0;">
<h1 style="opacity: 1;">blue</h1>
</p>
The browser corrects for this mistake of nesting block-level elements within each other. The rendered DOM structure looks like:
<p style="opacity: 0;"></p>
<h1 style="opacity: 1;">blue</h1>
<p></p>
This correction happens because certain elements like p
and h1
are only allowed to contain phrasing content. When flow content like headings are introduced, the browser assumes there was a mistake in closing the paragraph before the heading, leading to the displayed correction.
If you try selecting the child element based on the parent with classes like this:
<p class="parent">
<h1 class="child">blue</h1>
</p>
.parent > .child {
color: blue;
}
You'll notice that the "child" element does not render as a child due to the opacity issue.
To summarize, a child cannot override the opacity of its parent, even at full opacity itself, as the parent element shields it from view. The seemingly working counter example actually displays incorrectly because the code is technically incorrect and corrected by the browser.