[css-transforms] Unify the definition of transform-style & 3D context

As a spin-off discussion from "[css-transforms] CSS3D breaks with
opacity flattening". Rik suggested me to file an issue to clarify the
definition of planes and how 3D content stacks together.

Before we start to define "planes", I think we should first start off
with the very basic definition of transform-style and 3D context,
which is a complete mess right now. I think it is pointless to discuss
anything else if we are not on the same page about which elements live
in the same space.

Here is a strikingly simple example to show what a mess it is:
http://jsbin.com/doyedeg/
<div style="transform-style:flat; width:100px; height:100px;
opacity:0.5; background:red;">
  <div style="transform-style:preserve-3d; width:100px; height:100px;
margin-left:50px; background:green; transform:translateZ(0);"></div>
  <div style="transform-style:preserve-3d; width:100px; height:100px;
margin-left:25px; margin-top:-50px; background:blue;
transform:translateZ(-1px);"></div>
</div>

As I summed up in row 2~4 of my comparison sheet
(https://goo.gl/5dgFza), Chromium, Firefox, and Safari stack the
layers all differently (RGB, RBG, BRG, respectively) because they
create 3D context differently. An oversimplified explanation is that
Chromium followed the TR spec, Safari followed the ED spec, while
Firefox stuck somewhere in between (but closer to TR in general).

I studied many of the unspecified corner cases as I worked on
Chromium's clean-room compositing implementation (a.k.a. SPv2), I feel
strongly that the ED's definition is a no-go, because it introduced
the "3D context penetration issue". For example, "6.1.4. Accumulated
3D Transformation Matrix Computation"(https://goo.gl/oKQpm2) is
ill-defined if the 3D-context-establishing element is not a containing
block.

In my opinion TR's definition is way more self-consistent, although it
does need some clarification. I would rephrase it this way:

transform-style is only applicable to elements that creates a stacking
context (i.e. with non-auto used z-index), as it modifies stacking
context behavior. The default value is 'flat'. A computed value of
'preserve-3d' forces stacking context, and establishes containing
block for all descendants.

A stacking context with transform-style:flat works like a traditional
stacking context, sorting its child stacking contexts by their
z-index. If a child stacking context has 3D transform, the depth
component resulting from the transform is unused.

A stacking context with transform-style:preserve-3d propagates up
descendant planes created by 3D transforms if the parent stacking
context also has transform-style:preserve-3d. If its parent stacking
context has transform-style:flat, the inherited screen-space matrix
gets flattened. The collection of planes are sorted by depth and
composited with src-over.

To summarize, we have the following cases for an element:
A. z-index:auto && position:static : Normal flow
B. z-index:auto && !position:static : Pseudo stacking context
C. !z-index:auto && transform-style:flat && !3D-transformed:
Traditional stacking context, sorted child stacking contexts by
z-index.
D. transform-style:preserve-3d && parentSC.transform-style:flat :
Establishes 3D context. The flattened result sort with sibling
stacking contexts by its z-index. Establishes a default plane and root
stacking context for that plane.
E. transform-style:preserve-3d &&
parentSC.transform-style:preserve-3d: Inherit 3D context

Also if an element has 3D transform [#1] and it's parent stacking
context has transform-style:preserve-3d, its stacking context subtree
gets popped into a plane thus are not sorted against other sibling
stacking contexts. Its z-index is unused except for tie-breaking.

Note [#1]: A transform is 3D if and only if it contains any 3D
operation, even if if the computed local matrix has no depth
component. For example translateZ(0) is considered 3D.

Received on Monday, 26 September 2016 23:23:27 UTC