That sounds like it (er, the problem) but I'm not sure I follow the
reasoning. Why should opacity (or anything else) affect a stacking
order established by z-index?
Because of the way opacity is defined.
If you set opacity: 0.5 on an element, it's supposed to look as
though that element _and all its descendents_ were rendered into a
temporary buffer that was then blended on top of whatever the element
is on top of with an opacity of 0.5.
If the element didn't start a stacking context, then its descendents
could be interleaved with other "foreign" elements from different
stacking contexts that have full opacity.
This creates a contradiction. If those foreign elements are rendered
into the temporary buffer, then they will end up partially
transparent, which they shouldn't be as they are not descendents of
anything with opacity not equal to 1.0.
But if they are not rendered into the temporary buffer, then they
can't be interleaved with the descendents of the opacity: 0.5 element
and that would break the rules for stacking order.
Here is an example:
<div id="one" style="opacity: 0.5">
<div id="two" style="z-index: 1"></div>
<div id="three" style="z-index: 3"></div>
</div>
<div id="four" style="z-index: 2"></div>
Suppose all divs are absolutely positioned, have widths, heights and
solid background colours, and overlap each other.
According to the rules as they stand, the browser does this (or
equivalent):
1. Paint #one into a temporary buffer
2. Paint #two on top of #one in that temporary buffer
3. Paint #three on top of #two
4. Blend the temporary buffer onto the screen at opacity: 0.5
5. Paint #four onto the screen.
The stacking order here is #one, #two, #three, #four (because #one
starts a stacking context).
But if opacity didn't start a stacking context, what would the
browser be expected to do?
1. Paint #one into a temporary buffer.
2. Paint #two into the temporary buffer.
3. Paint #four on top of #two, but somehow not into the temporary
buffer
[impossible because #two _is_ in the temporary buffer]
4. Paint #three on top of #four, into the temporary buffer
[impossible
because #four _isn't_ in the temporary buffer].
5. Blend the temporary buffer onto the screen at opacity: 0.5
The stacking order here would be #one, #two, #four, #three, on the
assumption that opacity didn't start a stacking context.