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.
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:
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.
The following following changes to the HTML5 specification are suggested.
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:
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 definition (and use) of "adjust foreign attributes" (including the table).
Remove the definition (and use) of "The "in foreign content" insertion mode"
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. There are cases where prefixed attributes are necessary inside of svg fragments, and it is important that those attributes are associated with the correct namespaces as defined in Namespaces in XML [XMLNS].
Example:
<!DOCTYPE html> <html> <head> <title>SVG and HTML name collisions</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny" width="300px" height="200px"> <title>A textarea</title> <desc>A textarea that illustrates the name collisions between svg and html</desc> <svg:textArea width="200" height="50" /> </svg> <body> <html>
The behavior of this state depends on the content model flag.
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.
Consume the next input character:
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:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
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.
When the insertion mode is " in body", tokens must be handled as follows:
...Create a new XML parser. Set the encoding to the character encoding used by the HTML parser.
Feed the XML parser the string starting with the character that triggered entry into the 'tag open' state and ending with the character that triggered emittance of the start tag token.
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:
For each element the XML parser parses, insert a foreign element with the namespace, name, and attributes of that 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:
This section is informative, and describes some of the possible integration points.
There has been some proposals regarding this already, see for example 'Applying SVG properties to non-SVG content'.
There is a strong need to provide a fallback mechanism. There are different kinds of fallback possible:
Since SVG already provides the first kind of fallback, this proposal presents options for achieving the second kind of fallback, feature fallback:
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:
type
attribute. This permits tight integration with APIs, functionality, etc.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.
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.
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>