|
|
Donner
C++20 SVG rendering library
|
The SVG <symbol> element defines reusable graphical content that can only be rendered when instantiated by a <use> element. In essence, a <symbol> acts like a template with its own coordinate system (similar to a nested <svg>), and the <use> element places an instance of that template into the document. This document details how <symbol>'s attributes (like width, height, viewBox, etc.) affect its rendering when instantiated by <use>, such as default sizing, coordinate system transformations, and alignment.
A <symbol> element establishes an SVG viewport for its contents.
<symbol> elements are not rendered directly, their width and height purely define the symbol's own viewport dimensions. By default, the User Agent applies overflow: hidden to symbols, so any content outside the symbol's viewport rectangle is clipped. If a symbol has no explicit size, its viewport will auto-expand (100%) in whatever context it's placed, and overflow clipping will occur at the bounds of that region.
If the symbol does not have a viewBox, its coordinate system is in the same absolute units as the parent SVG. In this case, setting a width/height on the symbol (or letting it default) defines the clipping region but does not scale the content. The symbol's content is drawn at a 1:1 scale in the symbol's own coordinates.
For example:
In summary, without a viewBox, the symbol's coordinates are interpreted directly in the parent user space, and the <use>'s width/height (if any) only affect the clipping region, not the content scale.
flowchart TD
question_wh_on_use{"`width/height on <use>?`"}
override_wh["Override <symbol> width/height"]
question_wh_on_symbol{"width/height on <symbol>?"}
sizes_to_viewport["Viewport set to 100% of the parent container or viewport (effectively covering the container)"]
viewport_explicit["Viewport = explicit width/height"]
question_viewBox{"viewBox on <symbol>?"}
viewport_scale["Scale content to placed region<br/>(respect preserveAspectRatio)"]
viewport_no_scale["No scaling"]
%% Flow
question_wh_on_use -- Yes --> override_wh
question_wh_on_use -- No --> question_wh_on_symbol
override_wh --> viewport_explicit
question_wh_on_symbol -- Yes --> viewport_explicit
question_wh_on_symbol -- No --> sizes_to_viewport
viewport_explicit --> question_viewBox
sizes_to_viewport --> question_viewBox
question_viewBox -- Yes --> viewport_scale
question_viewBox -- No --> viewport_no_scale
A <symbol> does not inherit any viewBox from its outer SVG; it must define its own viewBox if one is needed. The symbol's coordinate system is independent. When a symbol is referenced via <use>, it behaves as if an <svg> with its own viewport and viewBox were embedded at that point. Therefore, any viewBox on the outer SVG (or parent coordinate frames) does not automatically apply to the symbol's content.
If the symbol has a viewBox attribute, it defines an internal coordinate system for the symbol's contents (min-x, min-y, width, height of the viewBox). This is analogous to how an <svg> element's viewBox works, establishing a mapping from the symbol's internal "user" coordinates to its viewport. The presence of a viewBox is crucial for scaling behavior: it enables the content to scale to fit the viewport set by either the symbol's or the use's width/height.
Without a viewBox, a <use> element's width and height don't scale the content (as noted above).
When a symbol does have a viewBox, it behaves much like a mini SVG file. The viewBox defines the coordinate extents of the symbol's content and implicitly provides an aspect ratio. If the symbol's own width and height are specified, they define the viewport size into which the viewBox is scaled (by default). If the symbol's width/height are not specified (auto), and the <use> also doesn't specify them, then by spec the symbol's width/height default to "100%" of the context. In practice this means the symbol will stretch to fill the available area (for example, the parent SVG's viewport).
This scenario is less common in usage – typically either the symbol or the use will provide an explicit size – but it's defined for completeness.
<symbol> has the preserveAspectRatio attribute, just like an <svg> element. By default (if not specified), it uses the standard xMidYMid meet behavior, meaning the symbol's content is uniformly scaled to fit the viewport while preserving aspect ratio (centering the content and possibly letterboxing if aspect ratios differ).
If preserveAspectRatio="none" is on the symbol, the content will be stretched non-uniformly to fill the viewport dimensions, which can distort the graphics.
This attribute is considered when scaling the symbol's viewBox to the viewport (whether the viewport came from the symbol's own width/height or from the <use>). It does not inherit from any outer context; it's a property of the symbol itself.
When a <use> instantiates a symbol, several coordinate system transformations occur in sequence:
Accumulated Transformation: The net effect of all the above is a combined transformation from the symbol's original content coordinates to the final user space of the document. The SVG2 spec describes this as the "cumulative effect" of the symbol's x, y, and its transformations, together with the host <use> element's transformations. Summarizing the chain:
All these contribute to the final positioning. Notably, the symbol's content never inherits transforms or coordinate scaling from outside the <use> – it's encapsulated. The outer SVG's coordinate system only comes into play at the moment the <use> places the symbol (through the <use>'s x, y, and transform). This encapsulation is why the symbol behaves like an independent nested SVG.