Inline SVG in HTML5 and XHTML

W3C SVG WG Proposal

Editors:
Erik Dahlström, Opera Software ASA <ed@opera.com>
Anthony Grasso, Canon Information Systems Research Australia, <anthony.grasso@research.canon.com.au>
Doug Schepers, W3C <schepers@w3.org>
Authors:
The authors of this document are the participants of the W3C SVG Working Group.

Abstract

The SVG language was created to meet developer and user needs for full-featured, open, and intuitive vector-graphics functionality for the Web. It was developed over time in response to community and vendor needs. From its inception, it was intended to integrate with and extend other prominent open Web platform technologies, such as X/HTML, CSS, and Javascript. It provides animation and interactivity in both declarative and scripted modes, filter effects, gradients, fonts, and many other features.

However, due to delayed implementation by major browsers and reliance on limited plugins, integration with HTML, particularly with inline SVG, was incomplete; consequently, many features for combining the two formats were underspecified or inconsistently implemented. With the increased native uptake of the SVG technology in major browsers, and the renewed development of HTML in browsers, a new opportunity has arisen for integration.

SVG is an XML language by design, and therefore has certain abilities and constraints at the syntactic level that are dissimilar to those of text/html (but consistent with XHTML); therefore, to work correctly, with the full range of features, SVG must follow the syntactic rules with which it was designed, in both HTML and XHTML. This consistency will aid developers, who will not need to learn two separate sets of rules for the syntax and feature sets. It will maintain compatibility with existing SVG viewers, and continue to permit round-tripping in SVG authoring tools such as Inkscape, Adobe Illustrator, and CorelDraw, which rely on the XML format.

This document is a proposal for integrating SVG in both the text and XML serializations of HTML5. This proposal follows the model that works today in every major browser that supports XHTML (Firefox, Opera, and Safari), all of which also support SVG natively. It also works to a lesser extent in Internet Explorer, with the use of an SVG plugin (and a small bit of extra code). The SVG WG believes that this satisfies the spirit and the letter of the HTML5 Design Principles, particularly in the aspects of compatibility.

This proposal is fairly complete, but it does have some minor gaps yet to be filled in, and so more detail may follow. However the SVG WG believes that it meets and exceeds the basic requirements laid out by the editor for the HTML5 specification. The SVG WG is very interested in taking community feedback into account. Please send comments or questions to www-svg@w3.org, the public SVG email list.

Note that this is not a formally published document, nor is it on the Recommendation Track. It is merely an inter-group proposal. This document is a work in progress, and may change due to feedback.

Contents

  1. Summary
  2. Requirements and use-cases
  3. Changes to HTML5 Specification
    1. Make tokeniser case-preserving
    2. Handle XML Namespaces
    3. Remove the lists of attributes for case fixups
    4. Special considerations for element and attribute name collisions
  4. Fallback Mechanisms
    1. <ext> and <fallback> Elements
    2. <foreignObject> Element With <switch>
  5. Use of SVG Resources in HTML and CSS
  6. Examples and Tests

Summary

The SVG WG proposes to change the HTML5 specification so that SVG fragments are parsed by an XML parser.

In order for HTML to know when to start the XML parsing mode it needs to preserve the case of characters it reads, until it can determine if an element token is to be handled by the HTML5 parser or the XML parser [case-preserving tokeniser]. A requirement for namespaces in XML for the SVG fragments [xml-namespaces] is also added.

If an SVG fragment is not XML well-formed, the fragment will be repaired by closing all elements up to and including the element where XML parsing began, and then control is handed over to the HTML parser. The point where the HTML parsing resumes is the character that triggered an XML error, or the character that follows the closing tag for the element where XML parsing began if there was no error. [foreign-elements].

A non-wellformed SVG fragment may be partially displayed up to the point right before the error occurred. This allows authors to get a reasonably clear indication of where an error is. The alternative of having e.g the SVG fragment textcontent displayed if there's an error isn't very helpful to someone trying to understand why something isn't working because it doesn't indicate where the error is.

One problem with mixing HTML and SVG is that some elements and attributes have the same (case-insensitive) names. This proposal suggests that such clashes are handled by recommending authors to use prefixing inside of SVG fragments to avoid any problems with legacy user agents [name-collisions]. Going forward, HTML5 and SVG should strive to not introduce any new name-collisions.

By using an XML parser the following important requirements are met:

Requirements

  1. SVG should remain XML when inline in HTML.
  2. Should be able to take a conforming SVG document and paste its contents into an HTML document and have it be the same DOM. (That is, it should be possible for authors to create an SVG document in Inkscape, take the contents of the file, and include it directly in the HTML without having to munge its syntax to get it to work.) This includes script content.
  3. Should be able to take a conforming HTML document and copy the SVG fragment from it and paste it into a new file and that would be a conforming SVG document. (That is, it should be possible for authors to, when they come across an SVG-in-HTML fragment, copy and paste that source and open it up in Inkscape to edit.)
  4. Should be able to provide some sort of fallback mechanism for the SVG-in-HTML so that UAs that don’t know how to handle these SVG fragments will display the fallback.
  5. Should allow for unrestricted growth of the SVG language by the SVG specifications (though those specifications should also take into account the idea that SVG will, going forward, be used more commonly in concert with HTML). This means that there would be no "white list" of allowed SVG elements in HTML. It also means that the SVG spec should be more careful about element and attribute names going forward.
  6. Should allow for SVG Fonts to be included in HTML, and ideally to be usable in HTML text.
  7. Should attempt to avoid breaking existing text/html pages. However, this must be balanced with the need for a clean, sustainable architecture.
  8. Should specify a tolerant error handling model for the SVG content.

This proposal tries to address each of these requirements. By requiring that SVG fragments must be XML well-formed inside HTML means that it's possible to take most SVG content and paste it into HTML and have it work the same as if it was opened standalone (requirements #1, #2 and #3). Using an XML parser for SVG fragments means that requirements #5 and #6 are met. Requirement #8 can be met by HTML5 requiring that at least SVG 1.2 Tiny shall be supported, since that has a more tolerant error handling model than SVG 1.1. For SVG fonts to be usable when SVG is inline in HTML (requirement #6) the parser must know which namespace a particular element belongs to, this proposal recommends using an XML parser combined with support for namespaces in XML. For fallback behavior (requirement #4) it's proposed that a 'switch' element inside of the SVG fragment is used to isolate the markup that will be displayed by legacy UA:s. To avoid breaking existing text/html content while keeping a clean sustainable architecture for SVG is difficult, and the proposed solution is that invalid (xml non-wellformed) SVG fragments are partially repaired, and that the HTML parsing mode takes over at the point of failure.

Changes to the HTML5 Specification

The following following changes to the HTML5 specification are suggested.

Make tokeniser case-preserving

Remove hard coded table of case fixes for SVG elements and attributes (if still in the spec).

Merge the "U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z" and "U+0061 LATIN SMALL LETTER A through to U+007A LATIN SMALL LETTER Z" cases, using the definition for the latter, in:

Drop the "U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z" case in:

Change: When the steps below require the UA to insert an HTML element for a token, the UA must first create an element for the token in the HTML namespace, and then append this node to the current node, and push it onto the stack of open elements so that it is the new current node.

To:

When the steps below require the UA to insert an HTML element for a token, the token and all attribute tokens it contains are first normalized to lowercase [mapping A..Z to a..z]. If there are attribute tokens with the same name it is a parse error, discard all attribute tokens that are duplicates and the value that is associated with each such token (if any), keep the first occurrence of an attribute token whose name is duplicated. Then the UA must create an element for the normalized token in the HTML namespace, and then append this node to the current node, and push it onto the stack of open elements so that it is the new current node.

Remove the paragraph: When the user agent leaves the attribute name state (and before emitting the tag token, if appropriate), the complete attribute's name must be compared to the other attributes on the same token; if there is already an attribute on the token with the exact same name, then this is a parse error and the new attribute must be dropped, along with the value that gets associated with it (if any).

Handle XML Namespaces

Remove the definition (and use) of "adjust foreign attributes" (including the table).

Remove the definition (and use) of "The "in foreign content" insertion mode"

Special considerations for element and attribute name collisions

One problem with mixing HTML and SVG is that some elements have the same (case-insensitive) tagnames. In this proposal such clashes are reasonably well-defined because of the support for XML namespaces. However, in legacy HTML user agents such elements will be interpreted as HTML elements, which of course is not desirable. This problem can be worked around by using prefixes on the elements that have name clashes, such as the 'a', 'font', 'script', 'style', 'title' and 'textArea' elements. By prefixing the SVG elements they will not be interpreted as HTML elements by legacy HTML user agents, but will be interpreted as SVG elements by user agents implementing this proposal. The new clashes introduced in HTML5 (the 'audio' and 'video' elements) may be something that needs further discussion. For 'script' and 'style' inside of SVG fragments, the same rules apply as when the SVG fragment is in a standalone XML file, no special quirks should be applied to the css or script parsing when the SVG fragment is included inline in HTML.

Clashing attibutenames are believed to have more limited effects, but in particular it should be noted that SVG will continue to have case-sensitive attributenames, and that it is possible to do prefixing of attributes as well.

Example:

<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:xlink="http://www.w3.org/1999/xlink">
<head>
	<title>SVG and HTML name collisions</title>
</head>
<body>
  <svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" width="300px" height="200px">
    <title>Bar Chart</title>
    <desc>A bar chart showing values for relative value of garlic, cheese, and ice cream</desc>
    <svg:textArea width="200" height="50" xmlns:svg="http://www.w3.org/2000/svg"/>
  </svg>
<body>
<html>

Sections of specification with changes

9.2.4 Tokenisation

Tag open state

The behavior of this state depends on the content model flag.

If the content model flag is set to the RCDATA or CDATA states

Consume the next input character. If it is a U+002F SOLIDUS (/) character, switch to the close tag open state. Otherwise, emit a U+003C LESS-THAN SIGN character token and reconsume the current input character in the data state.

If the content model flag is set to the PCDATA state

Consume the next input character:

U+0021 EXCLAMATION MARK (!)
Switch to the markup declaration open state.
U+002F SOLIDUS (/)
Switch to the close tag open state.
U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z and U+0061 LATIN SMALL LETTER A through to U+007A LATIN SMALL LETTER Z
Create a new start tag token, set its tag name to the input character, then switch to the tag name state. (Don't emit the token yet; further details will be filled in before it is emitted.)
U+003E GREATER-THAN SIGN (>)
Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+003E GREATER-THAN SIGN character token. Switch to the data state.
U+003F QUESTION MARK (?)
Parse error. Switch to the bogus comment state.
Anything else
Parse error. Emit a U+003C LESS-THAN SIGN character token and reconsume the current input character in the data state.
Close tag open state

If the content model flag is set to the RCDATA or CDATA states but no start tag token has ever been emitted by this instance of the tokeniser ( fragment case), or, if the content model flag is set to the RCDATA or CDATA states and the next few characters do not match the tag name of the last start tag token emitted (case insensitively), or if they do but they are not immediately followed by one of the following characters:

...then emit a U+003C LESS-THAN SIGN character token, a U+002F SOLIDUS character token, and switch to the data state to process the next input character.

Otherwise, if the content model flag is set to the PCDATA state, or if the next few characters do match that tag name, consume the next input character:

U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z and U+0061 LATIN SMALL LETTER A through to U+007A LATIN SMALL LETTER Z
Create a new end tag token, set its tag name to the input character, then switch to the tag name state. (Don't emit the token yet; further details will be filled in before it is emitted.)
U+003E GREATER-THAN SIGN (>)
Parse error. Switch to the data state.
EOF
Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F SOLIDUS character token. Reconsume the EOF character in the data state.
Anything else
Parse error. Switch to the bogus comment state.
Tag name state

Consume the next input character:

U+0009 CHARACTER TABULATION
U+000A LINE FEED (LF)
U+000C FORM FEED (FF)
U+0020 SPACE
Switch to the before attribute name state.
U+003E GREATER-THAN SIGN (>)
Emit the current tag token. Switch to the datastate.
EOF
Parse error. Emit the current tag token. Reconsume the EOF character in the data state.
U+002F SOLIDUS (/)
Switch to the self-closing start tag state.
Anything else
Append the current input character to the current tag token's tag name. Stay in the tag name state.
Before attribute name state

Consume the next input character:

U+0009 CHARACTER TABULATION
U+000A LINE FEED (LF)
U+000C FORM FEED (FF)
U+0020 SPACE
Stay in the before attribute name state.
U+003E GREATER-THAN SIGN (>)
Emit the current tag token. Switch to the data state.
U+002F SOLIDUS (/)
Switch to the self-closing start tag state.
U+0022 QUOTATION MARK (")
U+0027 APOSTROPHE (')
U+003D EQUALS SIGN (=)
Parse error. Treat it as per the "anything else" entry below.
EOF
Parse error. Emit the current tag token. Reconsume the EOF character in the data state.
Anything else
Start a new attribute in the current tag token. Set that attribute's name to the current input character, and its value to the empty string. Switch to the attribute name state.
Attribute name state

Consume the next input character:

U+0009 CHARACTER TABULATION
U+000A LINE FEED (LF)
U+000C FORM FEED (FF)
U+0020 SPACE
Switch to the after attribute name state.
U+003D EQUALS SIGN (=)
Switch to the before attribute value state.
U+003E GREATER-THAN SIGN (>)
Emit the current tag token. Switch to the data state.
U+002F SOLIDUS (/)
Switch to the self-closing start tag state.
U+0022 QUOTATION MARK (")
U+0027 APOSTROPHE (')
Parse error. Treat it as per the "anything else" entry below.
EOF
Parse error. Emit the current tag token. Reconsume the EOF character in the data state.
Anything else
Append the current input character to the current attribute's name. Stay in the attribute name state.
After attribute name state

Consume the next input character:

U+0009 CHARACTER TABULATION
U+000A LINE FEED (LF)
U+000C FORM FEED (FF)
U+0020 SPACE
Stay in the after attribute name state.
U+003D EQUALS SIGN (=)
Switch to the before attribute value state.
U+003E GREATER-THAN SIGN (>)
Emit the current tag token. Switch to the data state.
U+002F SOLIDUS (/)
Switch to the self-closing start tag state.
EOF
Parse error. Emit the current tag token. Reconsume the EOF character in the data state.
Anything else
Start a new attribute in the current tag token. Set that attribute's name to the current input character, and its value to the empty string. Switch to the attribute name state.
9.2.5.1. Creating and inserting elements

When the steps below require the UA to create an element for a token in a particular namespace, the UA must create a node implementing the interface appropriate for the element type corresponding to the tag name of the token in the given namespace (as given in the specification that defines that element, e.g. for an a element in the HTML namespace, this specification defines it to be the HTMLAnchorElement interface), with the tag name being the name of that element, with the node being in the given namespace, and with the attributes on the node being those given in the given token.

The interface appropriate for an element in the HTML namespace that is not defined in this specification is HTMLElement. The interface appropriate for an element in another namespace that is not defined by that namespace's specification is Element.

When the steps below require the UA to insert an HTML element for a token, the token and all attribute tokens it contains are first normalized to lowercase [mapping A..Z to a..z].

If there are attribute tokens with the same name it is a parse error, discard all attribute tokens that are duplicates and the value that is associated with each such token (if any), keep the first occurrence of an attribute token whose name is duplicated. The UA must then create an element for the normalised token in the HTML namespace. The newly created node must be appended to the current node and push it onto the stack of open elements so that it is the new current node.

The steps below may also require that the UA insert an HTML element in a particular place, in which case the UA must follow the same steps except that it must insert or append the new node in the location specified instead of appending it to the current node. (This happens in particular during the parsing of tables with invalid content.)

When the steps below require the UA to insert a foreign element for a token, the UA must first create an element for the token in the given namespace, and then append this node to the current node, and push it onto the stack of open elements so that it is the new current node.

9.2.5.10. The " in body" insertion mode

When the insertion mode is " in body", tokens must be handled as follows:

...
A start tag whose case-sensitive tag name is "math" that has a case-sensitive attribute "xmlns" with the value "http://www.w3.org/Math/1998/MathML":
A start tag whose case-sensitive tag name is "svg" that has a case-sensitive attribute "xmlns" with the value "http://www.w3.org/2000/svg":
A start tag whose case-sensitive tag name is "*:math" that has a corresponding case-sensitive attribute "xmlns:*" with the value "http://www.w3.org/Math/1998/MathML", where '*' can be any string as long as it's the same in both the tagname and the xmlns attributename:
A start tag whose case-sensitive tag name is "*:svg" that has a case-sensitive attribute "xmlns:*" with the value "http://www.w3.org/2000/svg", where '*' can be any string as long as it's the same in both the tagname and the xmlns attributename:

Save the tokeniser content model flag to old-state.

Create a new XML parser. Set the encoding to the character encoding used by the HTML parser.

Feed the XML parser the string corresponding to the start tag of the element along with all its attributes.

Let the XML parser attempt to parse and insert the foreign element. The namespace of the foreign element shall be decided by following namespaces in XML [XMLNS]. If the element was inserted successfully let it be the entry-point element.

If the previous step was successful, then bypass the tokeniser, and continue to feed the unmodified input stream character by character directly to the XML parser until it:

  1. returns with an error [XML10]
  2. closes the entry-point element, with no errors

For each element that is successfully parsed, the XML parser must insert a foreign element. The namespace of the foreign element shall be decided by following namespaces in XML [XMLNS].

If the XML parser returns an error:

If the XML parser returns with success upon closing the entry-point element:

Use of SVG Resources in HTML and CSS

This section is informative, and describes some of the possible integration points.

fonts
If SVGFonts are supported they should also be supported in HTML. The font definitions should be possible to include inline in the HTML (as parts of SVG fragments). Using SVGFonts in HTML is supported in WebKit.
paints (gradients, etc.)
It's possible to use SVG paintserver definitions (gradients, solid fills, stroking etc) in HTML. If these properties apply to HTML elements it would be possible to easily do text with gradient fills, text stroking, or custom pattern fills. And it would be possible to dynamically update the fill/stroke on HTML elements by requiring that any updates of the paintserver definition (or in the subtree it points to) applies immidiately to the elements that use the property.
filters, masking and clipping
All of the clipping, masking and filter definitions in SVG can be applied to HTML if it is defined how the effects apply in the css box model.
SVG in img element
Since img elements are traditionally used for raster images, the SVG images included by an img element receive no events, and they behave like any other raster image. Scripting should be disabled for svg:s that are referenced from an img element. In being similar to other animated raster formats (such as animated gif images), any declarative animation inside the SVG will mean that the SVG is animated. This is supported in Opera 9.5. Usually if there is no 'viewBox' attribute an SVG image doesn't scale to fit the viewport, but for SVG-in-img Opera generates a 'viewBox' if there was none, but only if there was a 'width' and 'height' that had absolute values set on the referenced SVG element. The generated 'viewBox' is then '0 0 width height'. This makes using SVG images more similar to using other images, where the content is scaled to fit the dimensions of the img element.
SVG as background-image and list-image in css
For the background-image case, the SVG is rendered as a static image into the css content area [ACTION: find out if the border area makes more sense], and scripting is disabled. For the list-image case the SVG is rendered into an area that depends on the chosen font, and the lineheight. This is something that could benefit from a more strict definition. Both of these uses of SVG is supported in Opera 9.5.

There has been some proposals regarding this already, see for example 'Applying SVG properties to non-SVG content'.

Fallback Mechanisms

There is a strong need to provide a fallback mechanism. There are different kinds of fallback possible:

  1. Textual Corepresentation: For accessibility reasons, authors should have a clear text equivalent of any non-textual SVG content. The <title> and <desc> elements, either as a child of the SVG root element or any group or shape, provide this functionality in SVG.
  2. Feature Non-Support: For new features, such as inline SVG support in HTML, an author should have an option to provide a functional equivalent for those features. For example, since Internet Explorer doesn't yet support SVG natively, if an author includes an interactive SVG bar chart, they might wish to also provide an HTML <img> with a raster version, or an HTML table that provides the same information, or even a VML equivalent. This helps adoption of the new feature, since authors can use the new feature with more confidence that all users will see at least some version of the content; this helps ameliorate the chicken-and-egg problem, and allows creation of a critical mass of content to compel universal implementation. This is critical to the design principle of degrading gracefully.

Since SVG already provides the first kind of fallback, this proposal presents options for achieving the second kind of fallback, feature fallback:

<ext> and <fallback> Elements

As a fairly general point of extensibility to HTML and XHTML, this option would introduce a base container element, <ext>, and a child container element, <fallback>, to contain fallback content for the case of feature non-support. The <ext> element would allow for a change of parsing context from the text/html parsing, allowing content that has any defined and HTML5-mandated parsing model, e.g. XML, S-expressions, or LaTeX. Content of the <ext> element need not be prefixed with any namespace token (beyond the requirements of its own language rules). The <ext> element has a 'type' attribute to indicate the MIME type of the format or syntax; if the MIME Type is not supported by the User Agent, and if the <ext> element contains a <fallback> element with content that is supported by the User Agent then the content of the <ext> element should not be rendered, and the content of the <fallback> element should be rendered instead. The content of the <fallback> element should be in the host language (i.e. if the host language is HTML5, then fallback content should be HTML5).

The <ext> element is roughly equivalent to SVG's <foreignObject> element. For full compatibility of content, the <ext> and <fallback> elements should be supported by both text/html and application/xhtml+xml.

Pros:

Cons:

<html lang="en">
<head>
	<title>HTML Extensibility Test</title>
</head>
<body>
	<h1 id="test_of_extensibility">Test of Extensibility</h1>
	<p>This is a test of an extensibility point in text/html, with a fallback mechanism.</p>
	<ext type="image/svg+xml">
		<fallback>
			<img src="rasterEquivalent.png" alt="..."/>
			<style type='text/css'>
			   svg > * { display: none; }
		        </style>
		</fallback>
		<svg xmlns="http://www.w3.org/2000/svg"
		     xmlns:xlink="http://www.w3.org/1999/xlink"
		     width="100%" height="100%"
		     version="1.1">
			<title>My Title</title>
			<desc>schepers, 01-04-2008</desc>
			<circle id="circle_1" cx="75" cy="25" r="20" fill="lime" />
      			<text id='text_1' x='10' y='25' font-size='18' fill='crimson'>This is some text.</text>
		</svg>		
	</ext>
</body>
</html>

ED: Comments on this are here.

<foreignObject> Element With <switch>

SVG provides a mechanism to conditionally render content, the <switch> element, when combined with the requiredFeatures, requiredExtensions, and systemLanguage attributes. SVG also provides a <foreignObject> element, which can contain XHTML code, though a rendering model is not yet defined. Combining the <switch> element with a child <foreignObject> element, which is rendered conditionally on a lack of SVG support, will allow a User Agent to selectively render an HTML fallback.

The fallback will allow any arbitrary HTML (or other supported language) which might be suitable as a fallback. For example, it might contain an HTML <img> element with a raster equivalent, an image map, a table (as in the example below), structured text (paragraphs, lists, etc.), a default HTML form control (if substituting for a custom SVG control), or even a simple message telling the user to upgrade their browser.

Pros:

Cons:

<html lang="en">
<head>
	<title>HTML Extensibility Test</title>
</head>
<body>
	<h1 id="test_of_extensibility">Test of Extensibility</h1>
	<p>This is a test of a SVG support in text/html, with a fallback mechanism.</p>
	<svg xmlns="http://www.w3.org/2000/svg"
	     xmlns:xlink="http://www.w3.org/1999/xlink"
	     width="100%" height="100%"
	     version="1.1">
		<title>My Title</title>
		<desc>schepers, 01-04-2008</desc>
		<circle id="circle_1" cx="75" cy="25" r="20" fill="lime" />
     			<text id='text_1' x='10' y='25' font-size='18' fill='crimson'>This is some text.</text>

		<switch>
			<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#SVG">
				<!-- empty group that gets selected if UA supports SVG, so no fallback is needed -->
			</g>
			<g>
				<!-- fallback HTML equivalent that browser will render if it doesn't support the SVG switch functionality -->
				<img src="rasterEquivalent.png" alt="..." xmlns="http://www.w3.org/1999/xhtml"/>
			</g>
		</switch>
	</svg>		
</body>
</html>

Note that the entire SVG fragment (including the fallback content) must be well-formed, otherwise both the SVG and the fallback content may be displayed.

Examples and Tests

SVG chart with HTML table fallback

XHTML version:

<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:xlink="http://www.w3.org/1999/xlink">
<head>
	<title>SVG in HTML Test</title>
</head>
<body>
	<h1 id="test_of_extensibility">Test of Extensibility</h1>
	<p>This is a test of a SVG support in text/html, with a fallback mechanism.</p>

    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" width="300px" height="200px">
		<title>Bar Chart</title>
		<desc>A bar chart showing values for relative value of garlic, cheese, and ice cream</desc>
    </svg>

	<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
		viewBox="-45 -41 540 492" width="500" height="500" font-family="Verdana">
		<title>Best Foods</title>
		<desc>The 3 best foods by popularity.  A pie chart showing values for relative value of garlic, cheese, and chocolate.</desc>

		<g id="cheese" fill="rgb(97, 115, 169)">
			<title>Cheese: 47.5%</title>
			<desc>287</desc>
			<path id="cheese-slice" d="M225,197.5 L225,46.75 A150.75,150.75 0 0 1 248.4,346.4 Z" stroke="black"/>
			<text x="390.3" y="189.2" font-size="14" fill="black" pointer-events="none" text-anchor="middle">287</text>
			<g id="cheese-legend">
				<rect x="10" y="385" width="20" height="10" rx="5" ry="5" stroke="rgb(0, 0, 49)" stroke-width="2"/>
				<text x="35" y="394" font-size="12" fill="black" stroke="none">Cheese: 287</text>
			</g>
		</g>
		<g id="chocolate" fill="rgb(152, 52, 28)">
			<title>Chocolate: 33.8%</title>
			<desc>204</desc>
			<path id="chocolate-slice" d="M225,197.5 L248.4,346.4 A150.75,150.75 0 0 1 85.8,139.5 Z" stroke="black"/>
			<text x="94.6" y="304.5" font-size="14" fill="black" pointer-events="none" text-anchor="middle">204</text>
			<g id="chocolate-legend">
				<rect x="153" y="385" width="20" height="10" rx="5" ry="5" stroke="rgb(32, 0, 0)" stroke-width="2"/>
				<text x="178" y="394" font-size="12" fill="black" stroke="none">Chocolate: 204</text>
			</g>
		</g>
		<g id="garlic" fill="rgb(141, 166, 66)">
			<title>Garlic: 18.7%</title>
			<desc>113</desc>
			<path id="garlic-slice" d="M225,197.5 L85.9,139.5 A150.75,150.75 0 0 1 224.9,46.75 Z" stroke="black"/>
			<text x="133.1" y="64.2" font-size="14" fill="black" pointer-events="none" text-anchor="middle">113</text>
			<g id="garlic-legend">
				<rect x="296" y="385" width="20" height="10" rx="5" ry="5" stroke="rgb(21, 46, 0)" stroke-width="2"/>
				<text x="321" y="394" font-size="12" fill="black" stroke="none">Garlic: 113</text>
			</g>
		</g>

		<switch>
			<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#SVG">
				<!-- empty group that gets selected if UA supports SVG, so no fallback is needed -->
			</g>
			<foreignObject>
				<!-- fallback HTML equivalent that browser will render if it doesn't support the SVG switch functionality -->
				<table border="1" cellspacing="0" cellpadding="5" xmlns="http://www.w3.org/1999/xhtml">
					<caption>Best Foods</caption>
					<tr><th>Food</th><th>Fans (in millions)</th><th>Percentage of Total</th></tr>
					<tr><td>Cheese</td><td>287</td><td>47.5%</td></tr>
					<tr><td>Chocolate</td><td>204</td><td>33.8%</td></tr>
					<tr><td>Garlic</td><td>113</td><td>18.7%</td></tr>
				</table>	
			</foreignObject>
		</switch>
	</svg>	

	<p>The chart should be rendered above this text.</p>

</body>
</html>

text/html version:

<head>
	<title>SVG in HTML Test</title>
</head>
<body>
	<h1 id=test_of_extensibility>Test of Extensibility</h1>
	<p>This is a test of a SVG support in text/html, with a fallback mechanism.

    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" width="300px" height="200px">
		<title>Bar Chart</title>
		<desc>A bar chart showing values for relative value of garlic, cheese, and ice cream</desc>
    </svg>

	<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
		viewBox="-45 -41 540 492" width="500" height="500" font-family="Verdana">
		<title>Best Foods</title>
		<desc>The 3 best foods by popularity.  A pie chart showing values for relative value of garlic, cheese, and chocolate.</desc>

		<g id="cheese" fill="rgb(97, 115, 169)">
			<title>Cheese: 47.5%</title>
			<desc>287</desc>
			<path id="cheese-slice" d="M225,197.5 L225,46.75 A150.75,150.75 0 0 1 248.4,346.4 Z" stroke="black"/>
			<text x="390.3" y="189.2" font-size="14" fill="black" pointer-events="none" text-anchor="middle">287</text>
			<g id="cheese-legend">
				<rect x="10" y="385" width="20" height="10" rx="5" ry="5" stroke="rgb(0, 0, 49)" stroke-width="2"/>
				<text x="35" y="394" font-size="12" fill="black" stroke="none">Cheese: 287</text>
			</g>
		</g>
		<g id="chocolate" fill="rgb(152, 52, 28)">
			<title>Chocolate: 33.8%</title>
			<desc>204</desc>
			<path id="chocolate-slice" d="M225,197.5 L248.4,346.4 A150.75,150.75 0 0 1 85.8,139.5 Z" stroke="black"/>
			<text x="94.6" y="304.5" font-size="14" fill="black" pointer-events="none" text-anchor="middle">204</text>
			<g id="chocolate-legend">
				<rect x="153" y="385" width="20" height="10" rx="5" ry="5" stroke="rgb(32, 0, 0)" stroke-width="2"/>
				<text x="178" y="394" font-size="12" fill="black" stroke="none">Chocolate: 204</text>
			</g>
		</g>
		<g id="garlic" fill="rgb(141, 166, 66)">
			<title>Garlic: 18.7%</title>
			<desc>113</desc>
			<path id="garlic-slice" d="M225,197.5 L85.9,139.5 A150.75,150.75 0 0 1 224.9,46.75 Z" stroke="black"/>
			<text x="133.1" y="64.2" font-size="14" fill="black" pointer-events="none" text-anchor="middle">113</text>
			<g id="garlic-legend">
				<rect x="296" y="385" width="20" height="10" rx="5" ry="5" stroke="rgb(21, 46, 0)" stroke-width="2"/>
				<text x="321" y="394" font-size="12" fill="black" stroke="none">Garlic: 113</text>
			</g>
		</g>

		<switch>
			<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#SVG">
				<!-- empty group that gets selected if UA supports SVG, so no fallback is needed -->
			</g>
			<foreignObject>
				<!-- fallback HTML equivalent that browser will render if it doesn't support the SVG switch functionality -->
				<table border="1" cellspacing="0" cellpadding="5" xmlns="http://www.w3.org/1999/xhtml">
					<caption>Best Foods</caption>
					<tr><th>Food</th><th>Fans (in millions)</th><th>Percentage of Total</th></tr>
					<tr><td>Cheese</td><td>287</td><td>47.5%</td></tr>
					<tr><td>Chocolate</td><td>204</td><td>33.8%</td></tr>
					<tr><td>Garlic</td><td>113</td><td>18.7%</td></tr>
				</table>	
			</foreignObject>
		</switch>
	</svg>	

	<p>The chart should be rendered above this text.


</body>
</html>