SVG Support

SVG elements are supported for usage as background-image and as source for <img> nodes. Starting with version 1.15 inline SVGs are available as well.

The feature set that is supported is a large subset of the SVG Tiny 1.2 specification. SVG elements can be styled and animated, using standard CSS.

The most notable sections from the specification that are missing are:

  • 10 Text
    • Basic support for <text> nodes. No other properties/nodes are supported.
    • <tspan> nodes are ignored and the text in them is a part of the parent <text> node.
  • 12 Multimedia
    • No multimedia support.
  • 13 Interactivity
    • No interactivity support.
  • 14 Linking
    • Support for xlink:href attribute in <use> elements; The newer version href is not supported.
  • 15 Scripting
    • No support for <handler>, or <listener> elements.
  • 16 Animation
    • No SMIL animation support. CSS/web animations can be used instead.
  • 17 Fonts
    • No support for SVG fonts.
  • 18 Metadata
    • No support for metadata.
  • 19 Extensibility
    • No extensibility support (i.e. no <foreignObject> elements).

SVG elements support

Element typeNotes
<circle>
<defs>
<desc>
<ellipse>
<g>
<line>
<linearGradient>
<path>
<polygon>
<polyline>
<radialGradient>
<rect>
<solidcolor>* Deprecated in the web standard, but supported.
<stop>
<style>
<svg>
<text>
<title>
<use>
<mask>* See the notes below
* Gradients applied on use elements follow the color stops, as if defined in the coordinate space of the used element.
* Does not create Shadow DOM yet, uses alternative methods for displaying the linked node.

Notes on the <mask> element support:

  • SVG elements cannot have mask=url(#...) and clip-path=url(#...) simultaneously,
  • <mask> elements do not support the mask-type property.
  • <mask> elements support only alpha masking mode (mask-type=alpha)
  • <mask> elements support only the attributes x, y, width, height, maskContentUnits, and maskUnits
  • <mask> elements must always have their x, y, width, and height specified. The default usage should be <mask id="maskId" x="0%" y="0%" width="100%" height="100%">...</mask>

SVG attributes support

AttributesNotes
fill
fill-opacity
viewport-fill
viewport-fill-opacity
stroke-opacity
stroke-width
stroke-linecap
stroke-linejoin
stroke-miterlimit
stroke
xml:space
stop-opacity
stop-color
fill-ruleParsed, but not used at this point. Only “even-odd” fill rule is supported.
rx
ry
x
y
x1
y1
x2
y2
cx
cy
r
points
preserveaspectratio
viewbox
xlink:hrefNo support for the newer href
gradientunits
offset
solid-opacity
solid-color
stroke-dashoffset
stroke-dasharray
d
width
height
font-size
transform
style

“Duplicated” SVG attributes / CSS properties

The following SVG attributes have the same name as standard CSS properties, but need to be parsed differently:

  • width
  • height
  • font-size
  • transform

The most notable difference is that you need to include measurement units (e.g. px, em, etc.) in CSS properties, while SVG attributes are unitless and it’s an error to specify the units. There are a few more differences in the transform property, as it can define a transform-origin in the SVG variant.

You don’t need to worry about defining CSS keyframe animations, except when using the “duplicated” properties. See the Animation section below for more details.

Using the inspector

  • Node’s internal text cannot be changed through the inspector (attributes can be changed).
  • Hovering elements within the svg element root won’t be highlighted.
    • This is due to the internal representation of SVG nodes (they do not exist in the Layout tree). Support for this is not planned at the moment.

Animation

Standard CSS animations are supported for animating inline SVGs.

There are two important shortcomings to note:

  • Several CSS properties use the same name as SVG ones but are parsed differently. For example, width in standard CSS must include the units in which the width is specified, while SVG’s width must not. Due to internal specifics, when defining keyframe animation for such “duplicated” properties, you must include the units, even though you shouldn’t by standard. Note how the y property (which is available for SVGs only) doesn’t have units specified, while width needs px.
@keyframes moving-rect {
  0% {
    y: 0;
    width: 85px;
  }
  100% {
    y: 100;
    width: 125px;
  }
}
  • Interpolating between 2 paths containing elliptical arc curves (A / a commands) is not guaranteed to be interpolatable, even if they contain the same types of commands. This is because elliptical arcs are converted to up to 4 quadratic Bezier curves, leading to possible differences in the internal path representation. Paths that have the same types of internal commands are the only ones that can be interpolated. For example, M 10,30 A 20,20 0,0,1 50,30 cannot be interpolated with M 10,30 A 40,20 0,0,1 50,30, because the first path’s arc is converted to 2 Bezier curves while the second is converted to a single one. If possible, avoid using elliptical arcs and use quadratic/cubic curves.

Performance optimizations

SVGs are internally cached when one of the following conditions is satisfied:

  • coh-use-aa-geometry is disabled (default: enabled)
  • The content size of the SVG does not exceed 1024x1024, and in the case of a non-inline SVG element, background-repeat is not set to no-repeat

SVGs are re-tessellated and redrawn when one of the following conditions is satisfied:

  • The content rectangle has changed (e.g., as a result of an animated element)
  • The element has been invalidated because of a change in the style of an SVG node

Inline SVGs are never cached in GPU textures. They completely follow the redraw rules as the other DOM elements, in other words, they are redrawn only if a region of their content is dirty.

Example:

<!DOCTYPE html>
<html>
	<style>
		.cached1 {
			width: 300px;
			height: 300px;
			background-image: url("cohtml.svg");
		}
		.cached2 {
			width: 2048px;
			height: 2048px;
			background-image: url("cohtml.svg"); /* 800x600 content size */
		}
		.cahced3 {
			width: 300px;
			height: 300px;
		}
		.cahced4 {
			width: 300px;
			height: 300px;
			background-repeat: no-repeat;
		}
		.non-cached1 {
			width: 300px;
			height: 300px;
			background-image: url("cohtml.svg");
			background-repeat: no-repeat;
		}
		.non-cached2 {
			width: 300px;
			height: 300px;
			background-image: url("cohtml-large.svg"); /* 2048x2048 content size */
		}
	</style>
	<body>
		<!-- Cached, since the content rectangle of `cohtml.svg` does not exceed 1024x1024. The element size is irrelevant. -->
		<div class="cached1"></div>
		<div class="cached2"></div>

		<!-- Inline images are also cached. The `background-repeat` property is ignored here. -->
		<img class="cached3" src="cohtml.svg">
		<img class="cached4" src="cohtml.svg">

		<!-- Not cached, since the `background-repeat` property is set to `no-repeat`. -->
		<div class="non-cached1"></div>

		<!-- Not cached, since the content rectangle of `cohtml-large.svg` exceeds 1024x1024. The element size is irrelevant. -->
		<div class="non-cached2"></div>
	</body>
</html>