[svgwg] Outline placement on `<tspan>` and other SVG inline text content elements is undefined; engines diverge (#1126)

karlcow has just created a new issue for https://github.com/w3c/svgwg:

== Outline placement on `<tspan>` and other SVG inline text content elements is undefined; engines diverge ==
Simple test and results:

```
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
  <style>
    text  { font: 50px sans-serif; }
    tspan { outline: 1px solid black; }
  </style>
  <text x="100" y="20" writing-mode="tb"><tspan>X</tspan></text>
</svg>
```

All three browsers disagree.

| Engine | Outline matches… | Notes | Rendering |
| --- | --- | --- | --- | 
| **Blink (Chrome 150)** | enclosing rect of (glyph ink bounds ∪ SVG text fragment rect), unioned across the inline's fragments | Source: `LayoutSVGInline::AddOutlineRects` calls `PhysicalRect::EnclosingRect(ObjectBoundingBox())`, where `FragmentItem::ObjectBoundingBox` for SVG text is `Union(ink_bounds, scaled_rect)` (the SVG fragment rect). For typical narrow Latin glyphs this overlaps the `getExtentOfChar` glyph cell but is not normatively the same rectangle. | <img width="143" height="83" alt="Image" src="https://github.com/user-attachments/assets/c3774fba-d914-472a-b136-44d800380a31" /> |
| **Gecko (Firefox 152)** | no outline rectangle drawn around the `<tspan>` glyphs | Source: `SVGTextFrame::BuildDisplayList` (`layout/svg/SVGTextFrame.cpp`) calls `DisplayOutline` for the `<text>` frame itself and then appends a single composite `DisplaySVGText` item. It overrides `SVGDisplayContainerFrame::BuildDisplayList`, which would have recursed into children via `BuildDisplayListForNonBlockChildren`. As a result, the inline frames for `<tspan>` and other SVG text content descendants never have `BuildDisplayList` called and never produce a `nsDisplayOutline` item. Outline on the parent `<text>` *is* painted; outline on `<tspan>` is dropped by design. | <img width="102" height="69" alt="Image" src="https://github.com/user-attachments/assets/ea39c0dd-fbdd-460b-9947-84a3160567a7" /> |
| **WebKit (Safari, current)** | rectangle of swapped/mirrored shape — does not enclose the glyph | known bug, fixed by [WebKit PR #66398](https://github.com/WebKit/WebKit/pull/66398). Post-fix, the painted rectangle is the legacy SVG inline box's frame rect, which derives from `SVGInlineTextBox::calculateBoundaries` (text fragment extents). Close to Blink for typical glyphs, not provably identical. | <img width="131" height="105" alt="Image" src="https://github.com/user-attachments/assets/9485a40e-d273-4efb-b91c-129f059fbb6c" /> |

**BUT**

CSS UI 4 / [3 The Outline Properties](https://drafts.csswg.org/css-ui/#outline) is deliberately permissive about where an outline goes:

> "This specification does not define the exact position or shape of the outline, but it is typically drawn immediately outside the border box."

The only normative requirements are that the outline (a) [encloses all the element's boxes](https://drafts.csswg.org/css-ui/#outline) and (b) is fully connected.

For SVG inline text content elements (`<tspan>`, `<textPath>`, `<a>` inside `<text>`), there is no formal CSS box model "border box": the rendered content is the set of glyph cells produced by the [SVG 2 §11 text layout algorithm](https://w3c.github.io/svgwg/svg2-draft/text.html). SVG 2 references CSS UI for outline (via the standard property table) **but does not say which "box" outline encloses on inline text content elements.**


## WHAT DO WE DO?

For an SVG inline text content element, which rectangle does the CSS `outline` enclose?

1. **Glyph cell union** — the union of `getExtentOfChar(reftests` for each `charnum` in the element's typographic characters. Matches Blink and post-fix WebKit. Aligns with how CSS Inline 3 conceptually treats inline content's outer extent.
2. **Glyph ink bbox** — the rectangle of inked pixels only. Tighter; arguably surprising when the glyph has whitespace advance or is sideways with extra cell space.
3. **Outline suppressed on SVG inline text** — i.e., interpret `outline` as not applying meaningfully here.
4. **Status quo** — implementation-defined. Authors cannot reason about outlines on SVG text and reftests are not portable.


There is nothing much into [Appendix C: Accessibility Support](https://w3c.github.io/svgwg/svg2-draft/access.html)

Please view or discuss this issue at https://github.com/w3c/svgwg/issues/1126 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Monday, 8 June 2026 08:27:14 UTC