- From: Jonathan Watt <jwatt@jwatt.org>
- Date: Mon, 26 Oct 2009 04:01:10 +0100
- To: www-svg <www-svg@w3.org>
Hi list, Here's my first pass at some spec text to define 'z-index' behavior for SVG. Note that Andrew Emmons has made a different proposal to create a new property with similar functionality to z-index on the Working Group's public list: http://lists.w3.org/Archives/Public/public-svg-wg/2009OctDec/0027.html I would personally prefer that we try to define sensible behavior for 'z-index' in SVG before resorting to creating a new property with similar yet different behavior, and I think what follows actually turns out to be pretty reasonable. For authors and implementations that have to deal with both HTML and SVG - especially inline in the same document - it's especially desirable to avoid creating a new similar-yet-different property that would require authors to know about two different properties (and their models), and possibly require two different implementation strategies. Contrary to what I thought during the last F2F meeting, I now think that simplified stacking context behavior (as opposed to no stacking context behavior) is desirable. (Stacking contexts are explained below for those of you that are unfamiliar with them.) A couple of reasons for this are: * To have sane behavior, avoiding excessive implementation complexity and avoiding poor performance whenever 'z-index' (or whatever it's called) is used on descendant elements of an element that is clipped (implicitly or explicitly), filtered, masked or has an 'opacity' of less than 1. (For an implementation that supports inline SVG in HTML, that can mean every SVG element.) * Preventing fragments of supposedly self contained SVG that contains 'z-index' from interacting in unexpected ways with other content in a document. This is probably important in any SVG content of reasonable complexity, but also for any snippets of SVG content that should be able to be dropped into an arbitrary document, markers, symbols, SVG generated by JavaScript libraries for mash-ups, etc. The draft proposed text follows. It is broken up into two sections: first some informative text that would probably be best in a separate primer document; second the normative text intended for the spec. -Jonathan ----------------------------------------------------------------------- The following section is informative. SVG elements are normally painted in document order using the painters model (elements that come later in the document paint over the top of elements that came earlier in the document). However, sometimes it is desirable to be able to force an element to a higher or lower position visually without changing its position in the DOM tree. This functionality is provided by the 'z-index' property. Understanding the 'z-index' property involves understanding the terms "stack level" and "stacking context". Let's consider each in turn: The 'z-index' property moves an element up or down a conceptual z-axis into layers called "stack levels". By default all the elements in a document are in stack level 0. By setting 'z-index' on an element to an integer other than 0, an author can force an element into a higher or lower stack level, thereby pushing that element above or below the elements in other stack levels. Documents are rendered by painting each stack level in turn, from lowest to highest, and painting the elements in each stack level in document order (i.e. using the painters model). Here is a simple example: <svg xmlns="http://www.w3.org/2000/svg"> <rect x="0" width="100" height="100" fill="red" z-index="-1"/> <rect x="40" width="100" height="100" fill="lime"/> <rect x="80" width="100" height="100" fill="blue" z-index="1"/> <rect x="60" width="100" height="100" fill="aqua"/> <rect x="20" width="100" height="100" fill="yellow" z-index="-1"/> </svg> In this example there are three stack levels: -1, 0 (the default) and 1. The red and yellow rects are in stack level -1, the lime and aqua rects are in stack level 0 (the default), and the blue rect is in stack level 1. Going from lowest stack level to highest, and painting the elements in each stack level in document order, the painting order is: red, yellow, lime, aqua, blue. In addition to putting an element into a stack level, setting an element's 'z-index' property to an integer value also creates something called a "stacking context". A stacking context is a stack level container that groups together an entirely new set of stack levels for that element's descendants. A 'z-index' property on any descendant will then place that descendant into one of the stack level in this new stacking context (descendants go into its level 0 by default), not into the stack levels of the parent or any other stacking context. When an element that creates a new stacking context is painted, so is the new stacking context that it created, along with all of that stacking context's stack levels and the elements that they contain. Stacking contexts allow self contained document fragments to use z-index without needing to worry about their children interleaving badly with other elements (z-indexed or otherwise) in other parts of the document. In the following example, the z-index attribute on the 'g' element is set to zero. This creates a new stacking context to contain the 'g' element's children without moving the 'g' to a different level in the document's root stacking context: <svg xmlns="http://www.w3.org/2000/svg"> <g z-index="0"> <!-- this is a self contained graphic --> <rect x="40" width="100" height="100" fill="lime" z-index="1"/> <rect x="20" width="100" height="100" fill="yellow"/> </g> <rect x="60" width="100" height="100" fill="aqua"/> <rect x="0" width="100" height="100" fill="red" z-index="-1"/> </svg> The example's root stacking context contains two stack levels: -1 and 0. The red rect is in level -1, and the 'g' element and aqua rect are in level 0. Inside stack level 0, the 'g' element's z-index attribute creates a new nested stacking context at the 'g' for the 'g' element's children. In this child stacking context there are two stack levels: 0 and 1. The yellow rect is in level 0 (the default), and the lime rect is in level 1. Painting of this example starts with the stack levels of the root stacking context. First the red rect is painted in level -1, then in level 0 the 'g' element is painted followed by the aqua rect. When the 'g' element is painted, the child stacking context that its z-index created and all of that context's stack levels are also painted. In this child stacking context, first the yellow rect in level 0 is painted, followed by the lime rect in level 1. It's only after the 'g' and the stacking context that it creates has been painted that the aqua rect is painted. Note that this means that although the z-index of 1 for the lime rect is a higher value than the (implicit) z-index of 0 for the aqua rect, the containment provided by the 'g's child stacking context results in the aqua rect painting over the lime rect. The painting order is therefore: red, yellow, lime, aqua. Note that setting 'z-index' to an integer value is not the only way that a new stacking contexts is triggered for an element's descendants. See the normative text for a full list. ----------------------------------------------------------------------- The following section is normative. CSS specifies a property called 'z-index'. The CSS rules that define the effect of the 'z-index' property [1][2] were written specifically for the CSS box model, and those rules do not make sense as they stand for most SVG elements (most SVG elements do not participate in or establish a CSS box model layout). This section specifies how implementations must handle the 'z-index' property on elements in the SVG namespace. 'z-index' Value: auto | <integer> | inherit Initial: auto Applies to: all elements, but see prose * Inherited: no Percentages: N/A Media: visual Computed value: as specified * /Contrary to the rules in CSS 2.1, the 'z-index' property applies to all SVG elements regardless of the value of the 'position' property, with one exception: as for boxes in CSS 2.1, outer 'svg' elements must be positioned for 'z-index' to apply to them./ The 'z-index' property specifies: 1. The stack level of the element in the current stacking context. 2. Whether the element establishes a new local stacking context. Values have the following meanings: <integer> This integer is the stack level of the element in the current stacking context. The element also establishes a new local stacking context for its descendants. auto The stack level of the element in the current stacking context is the same as its parent element, unless its parent established a new stacking context, in which case its stack level is 0. The element does not establish a new local stacking context. A new stacking context must be established at an SVG element for its descendants if: * it is the root element * the 'z-index' property applies to the element and its computed value is an integer * the element is an outer 'svg' element, or a 'foreignObject', 'image', 'marker', 'mask', 'pattern', 'symbol' or 'use' element * the element is an inner 'svg' element and the computed value of its 'overflow' property is a value other than 'visible' * the element is subject to explicit clipping: * the 'clip' property applies to the element and it has a computed value other than 'auto' * the 'clip-path' property applies to the element and it has a computed value other than 'none' * the 'opacity' property applies to the element and it has a computed value other than '1' * the 'mask' property applies to the element and it has a computed value other than 'none' * the 'filter' property applies to the element and it has a computed value other than 'none' For a user friendly explanation of the terms "stack level" and "stacking context", see the z-index primer document. For the normative rules regarding how stacking contexts and stack levels affect SVG elements, see below. Stacking contexts and stack levels are conceptual tools used to describing the order in which elements must be painted one on top of the other when the document is rendered, and for determining which element is highest when determining the target of a pointer event. Stacking contexts and stack levels do not affect the position of elements in the DOM tree, and their presence or absence does not affect an element's position, size or orientation in the canvas' X-Y plane - only the order in which it is painted. Stacking contexts can contain further stacking contexts. A stacking context is atomic from the point of view of its parent stacking context; elements in ancestor stacking contexts may not come between any of its elements. Each element belongs to one stacking context. Each element in a given stacking context has an integer stack level. Elements with a higher stack level must be placed in front of elements with lower stack levels in the same stacking context. Elements may have negative stack levels. Elements with the same stack level in a stacking context must be stacked back-to-front according to document tree order. With the exception of the 'foreignObject' element, the back to front stacking order for a stacking context created by an SVG element is: 1. the background and borders of the element forming the stacking context, if any 2. child stacking contexts created by descendants with negative stack levels, primarily ordered by most negative first, then by tree order 3. descendants with 'z-index: auto' or 'z-index: 0', in tree order 4. child stacking contexts created by descendants with positive stack levels, primarily ordered by lowest index first, then by tree order Since the 'foreignObject' element creates a "fixed position containing block" in CSS terms, the normative rules for the stacking order of the stacking context created by 'foreignObject' elements are the rules in Appendix E of CSS 2.1. 1. http://www.w3.org/TR/CSS2/visuren.html#propdef-z-index 2. http://www.w3.org/TR/CSS2/zindex.html
Received on Monday, 26 October 2009 03:01:42 UTC