The paint-order property

  ·   In SVG 1.1, every shape and text element has its components painted in the same order: fill, then stroke and finally any markers. In some situations, authors want these to be painted in a different order. The usual workaround to achieve this is to duplicate the element, and have say a stroke but no fill set on the first and vice versa on the second.

SVG 2 adds a simple property that allows the author to control the painting order of the components of a shape or text content element: the paint-order property. The initial value of the property is normal, which gets you the default, SVG 1.1 behaviour. To specify a different order, a sequence of fill, stroke and markers keywords is used. The keywords cannot be repeated, but some can be omitted, in which case all of the remaining unspecified components are painted in their default order, after the ones that were explicitly specified. For example, paint-order="stroke" is equivalent to paint-order="stroke fill markers".

Where I often want to place the stroke underneath the fill is when stroking text. The problem with placing the stroke above the fill of a text element is that the stroke straddles the boundary of the fill, half lying inside the glyphs and half outside. This results in the apparent glyph shape changing, the thicker the stroke you use.

The following example demonstrates the use of paint-order on a <text> element to produce stroked text that looks nicer:

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="200">
  <linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
    <stop stop-color="#888"/>
    <stop stop-color="#ccc" offset="1"/>
  </linearGradient>
  <rect width="400" height="200" fill="url(#g)"/>
  <g fill="crimson" stroke="white" stroke-width="6" stroke-linejoin="round"
     text-anchor="middle" font-family="sans-serif" font-size="50px" font-weight="bold">
    <text x="200" y="75">stroke over</text>
    <text x="200" y="150" paint-order="stroke">stroke under</text>
  </g>
</svg>

The example would be rendered like this:

Perhaps this comparison is a bit unfair; the apparent thickness of the stroke on the element with paint-order="stroke" is half that of the text with the default paint-order since half of it is occluded by the fill. Here is what it would look like if the first text element had stroke-width="3":

It’s clearer to see here that due to the stroke paint intruding on the fill of the first text element, the red glyphs end up looking eroded, while those in the second element appear normal.

Implementation

Since bug 828805 landed yesterday, support for the paint-order property is now available in Firefox Nightly. It currently is enabled only when the svg.paint-order.enabled property is set to true, which is the default on the Firefox Nightly and Aurora channels. Once the SVG 2 specification matures further, support will be enabled across all channels.


Two comments

You can subscribe to the comment feed to follow the responses to this entry.

  1. Out of curiosity, does SVG have a stroke position property? (In other words, can the stroke be placed completely inside or outside the edge of the shape, rather than centered on the edge.)

  2. It does not at the moment, but it has been discussed for example in this mailing list thread. I think it’d be nice to have stroke-position too, though it’s bit harder for the implementation since it requires cooperation from the underlying graphics library that is doing the stroking for you.

Leave a comment