Early in 2005 I started getting interested in SVG, a web standard for vector graphics on web pages. My efforts in this direction were first sparked by a friend and later by the fact that modern browsers like Firefox and Opera have introduced SVG support. This entry is to serve as a guide so people can learn from my experiences. It was originally published in Dec 2005, but I will continue to update it as more items occur to me. It was last updated in Jan 2007.


[Edit: Updated 2007-01-19 for ASV Workarounds]

Introduction To SVG [TOC]

Since the very early days of the web, HTML has the capacity to display text and hyperlinks inline with graphics. For the most part, graphics have been GIF, JPEG and more recently PNG, which are all raster graphics - meaning the image file contains the pixel information that should be displayed. SVG and other similar formats (like Microsoft's VML) describe vector graphics, which describe their images in terms of mathematics (i.e. they tell the browser how to draw the image). The benefits of this are that vector graphics display perfectly at any resolution (i.e. "scalable") and, with some exceptions, can be described in less disk space. The tradeoff is some interpretation cost (i.e. rasterization) at the client end. With upcoming hardware acceleration (see OpenVG) this could be alleviated also.

Anyway, all that aside, if you need a brief introduction to SVG, please feel free to read my first two SVG Kickstart Tutorials: One and Two. They give an overview of basic SVG functionality including how to draw simple and complex shapes, tools you can use and why SVG is important. This blog entry will be focused on integrating SVG into your web pages and the current difficulties imposed by various platform implementations quirks and differences.

SVG Implementations [TOC]

At the time of my original foray into this experience (Spring of 2005), the most well-deployed implementation for SVG by far was Adobe's SVG Viewer (known as ASV), which is a plugin for most web browsers. In the last couple years, both Mozilla and Opera have included native SVG support and Safari is working away on it. As a result of my target implementation platforms for SVG are primarily :

  • Internet Explorer 6 (IE6) with Adobe SVG Viewer 3.0x and ASV 6 (pre)
  • Firefox 1.5+ with native SVG support
  • Opera 9+ with native SVG support

Note that Konqueror also has some support for SVG which is steadily improving.

Ok, here are some of the issues you'll face when integrating SVG with your HTML pages:


How To Include SVG Within HTML [TOC]

There are actually a lot of potential choices here. The following elements could support referencing an SVG image within an HTML page: <object>, <embed>, <img>, <iframe>. Furthermore, if you want to use an SVG image as a background or a list bullet, the CSS 'background-image' and 'list-style-image' are also candidates.

Now here's the ugly reality: No implementations currently support HTML <img> or CSS 'background-image' and 'list-style-image' [Update 2008-02-16: Opera 9.5 will support this]. This is unfortunate, since providing scalable backgrounds to <div>s within HTML pages could be a great way to get rounded corners on web pages instead of ugly hacks like this or waiting for CSS3 implementations. Anyway, without these, that leaves <object>, <iframe> and the non-standard <embed>.

Of the remaining candidates, <object> is the most reasonable solution because it allows fallback content to be displayed if the user agent does not support SVG rendering. This is important - if a user doesn't have a browser that supports SVG, they may not want to download Adobe's plugin, which means they can't see your content unless you can provide fallback content in terms of PNG or whatever.

However, in my experience ASV seems to have inconsistent results with <object>, while I have found that <embed> works reliably in ASV. Firefox and Opera do not like <embed> and seem to work reliably with <object>. Frustration! My experience with <iframe> is limited because I want to use <object>, but I do not know of any issues with it.

My solution to this dilemma was to provide <object> for non-IE browsers and <embed> in IE browsers. I had done this using some JavaScript that transforms <object> elements into <embed> elements if IE is used and ASV is installed. You can see the JS here.

The problem with this script is that it needs to be run when the page loads, which causes some delay in rendering and turns out to ultimately be unnecessary. Stefan Oskamp gave me the tip of using IE conditional comments. With this technique you can serve an <embed> to IE and an <object> to every other browser:

<!––[if IE]>
  <embed src='mysvgfile.svg'></embed>
<![endif]––>
<![if !IE]>
  <object data='mysvgfile.svg' type='image/svg+xml'>
    <p>Please download <a href='http://www.mozilla.com/firefox/'>Firefox 1.5</a>.<p>
  </object>
<![endif]>

One final point: Both Firefox and Opera provide a way to inline SVG with XHTML. This means that you can have an XHTML document with SVG elements inside it (not referenced to another document). The issue is that IE does not support XHTML or mixed XML grammars at this time (and is unlikely to for awhile). If you'd like to constrain your audience to just Firefox and Opera users, feel free to use XHTML with SVG content and keep your eye on the CDF Working Group.


How To Link Between SVG and HTML Documents [TOC]

The next issue I found was in managing hyperlinks across SVG and its parent HTML document.

Update 2007-01-17: In fairness, I should note that Opera 9 and Firefox 2 have fixed numerous issues with linking so that now a semi-sane solution is quite deployable. That means another year or two from now (when Opera 8 and Firefox 1.5 have faded from view), I can update my website. Such is the life of the web developer...

HTML provides support for hyperlinking using the <a> element. This element allows you to specify the target "frame" of the new link. In default cases, this means when you click on a link, the enclosing HTML frame gets replaced by the contents at the new link. If you're using HTML frames and you wish to replace the entire page (i.e. the "top" frame) you need to specify the target attribute to be equal to "_top".

SVG also provides support for hyperlinking within an SVG document using a similar <a> element. Unfortunately, the default targetting behavior when a link is accessed (clicked) is not consistent across implementations.

Let's say we have the following four files.

testcc.html:

<html><body>
  <p>This is the upper paragraph.</p>

  <!--[if IE]>
    <embed src='twolinks.svg'></embed>
  <![endif]-->
  <![if !IE]>
    <object data='twolinks.svg' type='image/svg+xml'>No SVG Support!</object>
  <![endif]>

  <p>This is the lower paragraph.</p>
</body></html>

twolinks.svg:

<?xml version='1.0'?>
<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>
  <a xlink:href='testtarget1.html'><text x='20' y='25' stroke='green'>Link 1</text></a>
  <a xlink:href='testtarget2.html'><text x='20' y='55' stroke="blue">Link 2</text></a>
</svg>

testtarget1.html:

<html><body><p>Test Target 1</p></body></html>

testtarget2.html:

<html><body><p>Test Target 2</p></body></html>

If you click on testcc.html you will see two paragraphs surrounding the SVG document (which contains two links). When you click on a SVG link in IE+ASV, the entire web page will be switched to the corresponding testtarget HTML document. If you click on a SVG link in Firefox or in Opera 8.x, only the SVG document will be switched out for the appropriate testtarget HTML document (in other words if you clicked on "Link 1", you'd have testtarget1.html embedded within testcc.html). Opera 9 TP actually switches this behavior to follow IE's approach.

I'm not clear on what the correct behavior is here - maybe it is unspecified, but I tend to side with Firefox and Opera 8.51 on this one. The SVG link is with respect to the document in which it is located (i.e. twolinks.svg) and not within a parent document. Behavior should be consistent whether the SVG document is linked to directly or referenced from within a containing HTML document.

Anyway, differences aside, the question becomes: How do I get consistent behavior?

For my experience, I actually WANTED an SVG link to result in the entire web page being switched for its target. In this respect, it should have been as simple as adding target="_top" to the svg:a elements as specified here.

<?xml version='1.0'?>
<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>
  <a xlink:href='testtarget1.html' target='_top'><text x='20' y='25' stroke='green'>Link 1</text></a>
  <a xlink:href='testtarget2.html' target='_top'><text x='20' y='55' stroke="blue">Link 2</text></a>
</svg>

Unfortunately, this does not work with either Firefox or Opera 8.x. What I did next was add in a JavaScript hack to get Firefox to work:

<?xml version='1.0'?>
<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>
  <a xlink:href='testtarget1.html' target='_top'>
    <text x='20' y='25' stroke='green' onclick="top.location.href='testtarget1.html';">Link 1</text>
  </a>
  <a xlink:href='testtarget2.html' target='_top'>
    <text x='20' y='55' stroke="blue" onclick="top.location.href='testtarget2.html';">Link 2</text>
  </a>
</svg>

Now it works properly in Firefox 1.5, but since Opera 8.x does not support JS scripting of the SVG DOM, the above hack does not work. What I resorted to then was a hack that I'm not proud of. Basically I put the following "frame-busting" JavaScript at the top of all my HTML pages by using some PHP templating:

  function bustFrames() {
    if (top != self) top.location.href = "<?php echo $_SERVER['PHP_SELF']; ?>";
  }

This works in Opera 8.x, but only partially. You still see the target document load up in the <object> frame and then almost immediately the entire page switches to the target document. What a fugly hack! Unfortunately, Opera 9 TP1 "fixes" this by resorting to switching the entire enclosing document for the target one, even if target is not specified. I will be in contact with Opera developers for them to fix this as I consider it a bug (i.e. they should support the standard specification).

It should be noted that the Compound Document Framework seeks to address issues like this and may be of interest.

How To Write Compliant SVG [TOC]

An unfortunate side effect of having Adobe's SVG Viewer become the defacto implementation is that ASV accepts noncompliant SVG documents. The biggest "mistake" I've seen is that ASV does not require XML namespaces to be bound.

Firefox requires the SVG namespace to be mentioned (bound) in the <svg> element. On the other hand, Opera's native implementation does not require this, meaning that Firefox may be right, but they are in the minority. Jonathan Watt (of the Firefox SVG team) has provided some great authoring guidelines that describe this and other issues for bringing SVG documents into compliancy.

Opera developers should follow Firefox's lead here and enforce stricter compliancy as well, otherwise the web will forever be littered with noncompliant SVG documents. We need to fix developer habits now. As XML grammars become further integrated, namespaces become a very important issue.

Working Around Adobe SVG Viewer [TOC]

I'm writing this section because I found these couple "gotchas" and I know others have stumbled across them as well. The Adobe SVG Viewer (ASV) actually uses a very old version of the Mozilla scripting engine, and there are a couple issues with this to keep in mind when writing SVG for ASV :

Beware Of The NodeList [TOC]

Some DOM methods like getElementsByTagName() return NodeList objects. A NodeList object is a collection of live DOM nodes that you can then work with. The JavaScript bindings state that NodeList objects can be operated on using the array-index operators (square-brackets) to get at an individual node. As a result, you'll often want to write code like this:

var allPaths = document.getElementsByTagName("path");
alert( allPaths[0].id );

Unfortunately this won't work in ASV because ASV does not support using square-brackets on NodeList objects. If you want code that works in Firefox, Opera and ASV, you should rewrite your code using the NodeList item() method instead like so:

var allPaths = document.getElementsByTagName("path");
alert( allPaths.item(0).id );

The above code will work in all fully-DOM compliant user agents as well as ASV.

setTimeout and setInterval [TOC]

JavaScript uses setTimeout() and setInterval() methods as ways to delay execution of code or repeatedly execute code. You will want to write code like this:

function func1(str) { alert(str); }
function func2() { alert("Five seconds!"); }

setTimeout(func1("howdy"), 2000); // call func1("howdy") after 2 secs
setInterval(func2, 5000); // call func2() every 5 secs

You can even do:

setTimeout(new function() { alert("howdy!"); }, 2000);

Unfortunately, ASV does not like this - ASV only expects a string as the first argument in the setTimeout() and setInterval() functions. This string will then be eval'ed and executed, so it's pretty close to the same thing, but not quite. So to make your code work in Firefox, Opera and ASV you should rewrite your code like this:

function func1(str) { alert(str); }
function func2() { alert("Five seconds!"); }

setTimeout("func1('howdy')", 2000); // call func1('howdy') after 2 seconds
setInterval("func2()", 5000); // call func2() every 5 seconds


§188 · January 19, 2007 · Firefox, JavaScript, Opera, Software, SVG, Technology, Web, XML · · [Print]

20 Comments to “Guide to Deploying SVG with HTML”

  1. You might (or not) like SVG inside HTML through scripting. Also, if “_self” is the default value for the “target” attribute what Opera does seems to be compliant per CDR. Now I’m not sure if that is correct as it seems to contradict the SVG specification. Oh well.

  2. sysrpl says:

    One thing that should be noted about inline SVG with XHTML is that you are required to do the following in order to get the browser to render inline SVG:

    Include a xml prologue as the first line of your document
    Have the content-type response header set to xml rather than default text/html

    Is you fail to do these things, the document will still validate as valid xhtml (just like this webpage), but the it will not render the SVG.

  3. Andrea says:

    Hi,
    pardon for the double post (here and in the other forum http://www.codedread.com) maybe my question will reach the right audience.
    First of all thanks for a well written and clear article.

    I’ve recently became interested in SVG and XML and XSLT technologies. I apologize in advance for my ignorance in this subject as I am sure that there is a LOT to learn and I only started to scratch the surface. Nevertheless.. here goes..

    Let’s suppose that I have an XML file that contains a vector like this:
    <VectorAttribute name=”path_x_data”>
    0 1 2 3 4 5 6
    </VectorAttribute>
    <VectorAttribute name=”path_y_data”>
    0 0 2 2 3 4 4
    </VectorAttribute>

    This represents a series of X,Y points.
    My intention is to create a dynamic chart of those points, and that’s why I started looking at SVG.
    Now.. your article describes how to create images directly in the XML file or HTML file (via the svg tag) or how to reference an SVG image, and shows how that tag is interpreted and displayed with a compliant browser.
    My question is: supposing that my XML file cannot be modified, can I use an XSLT file to handle the creation of charts/plots via SVG?
    In other words, if an XML file contained a vector, how can it be plotted so that a browser (like FireFox 1.5) will display the plot instad of the raw data? Does this make sense:
    XML + XSLT + SVG = HTML or formatted XML file where vectors are displayed as dynamic charts?
    Thanks!
    Andrea P.

  4. Jeff Schiller says:

    Hi, your post makes perfect sense, so you’re on the right track 😉

    Actually a colleague of mine (Rob) had worked on something similar here.

    Basically you can use XSLT to translate arbitrary XML into SVG (which is another XML grammar). This is a perfect use case for XSLT because (as you’ve said) the raw data is not modifyable. I am definitely no expert on XSLT but perhaps Rob can help you out there. It’s important that you understand that SVG describes the image, thus once you’ve got to SVG you’re done. Then you can just embed the SVG image in HTML by using the <object> tag.

  5. Todd Dominey says:

    The links to your kickstart tutorials return 404s. Or, at least a PHP document not formatted properly.

  6. Jeff Schiller says:

    Thank you, Todd. I’ve updated the links correctly now…

  7. There is another platform you might want to consider: Safari with Adobe SVG Viewer, which is probably the default platform on Macintoshes that have not installed Mozilla Firefox.

    My experience so far is that it works the same as ASV with Internet Explorer on windows, with the additional excitement that object tags cause Safari 1.0 to crash, so you have to use embed. People using Mac OS X 10.2 cannot upgrade Safari without paying to upgrade their operating system, so buggy Safari versions are likely to linger for a few years.

  8. Digitales says:

    Problem with IE and embed is that there is no way to display alternate content. It seems that you need svg viewer … instructions or you need svg viewer … instructions doesn’t work.

    So I decided to use you need svg viewer … instructions for all browsers
    and your svglib.js which is loaded only for IE browsers.
    I also modified the script a bit. Don’t know which is the best way to do this, but this looks cleaner.
    -snip-
    if(obj && obj.type == “image/svg+xml” && bDoEmbed)
    {
    // change it into an

    var embed = document.createElement(’embed’);
    embed.type = “image/svg+xml”;
    embed.src = obj.data;
    if(obj.id) {
    embed.id = obj.id;
    }
    if(obj.width) {
    embed.width = obj.width;
    }
    if(obj.height) {
    embed.height = obj.height;
    }

    objsToChange[objsToChange.length] = obj;
    newObj[newObj.length] = embed;
    }
    -snip-
    -snip-
    for(var i = 0; i

  9. Jeff Schiller says:

    Hi Digitales,

    I had the same quandary as you did about embed not having fallback content. I found a later solution was to use Condition Comments (to detect IE), try to create an Adobe SVG control, if so then use script to create the embed, if not use script to write the fallback content. I wrapped everything up into a PHP function too. You can see my current solution explained here: http://blog.codedread.com/archives/2006/01/13/inlaying-svg-with-html/.

    I think it covers all scenarios: IE+ASV, IE without ASV + JS enabled, IE with JS disabled and Firefox/Opera (using object).

    Regards,
    Jeff

  10. hukl says:

    Just for the record: Safari supports SVG natively as well 😉

  11. Jeff Schiller says:

    The nightly builds now do, yes (17 days after this article was published, SVG landed).

    Can you let me know how integration between HTML and SVG works? Do they use the object tag without any issues? Thanks.

  12. Noah Stern says:

    Thanks for posting this Jeff, it helped me a lot.

  13. Anand says:

    i could not access the javascript code which in HTML page from svg using TOP.function name.

    the case is SVG containing page is loaded in another page within a frame.

    so if we access using top it refers the top most parent, not the immediate parent.

    since svg doesn’t support parent, how to access the function which is in the immediate parent page.

  14. Jeff Schiller says:

    Anand,

    I’ve written an article on that which i believe should be published at the Opera developer’s site some time this month.

    In the meantime, please look into the SVG DOM as it contains the answers. http://www.w3.org/TR/SVG11/idl.html. The SVGDocument attribute defaultView points to the containing frame (Window element), the Window attribute frameElement points to the containing HTML:object element.

    Regards,
    Jeff

  15. Fabio says:

    Hi,
    I have a problem about the visualization of a SVG image!
    I have a jsp that generate my SVG image via a java class that transform a XML file with a XSL file in a SVG file. Then in the same page I include the SVG image into an HTML Object tag! But the image is not shown, I think because it is not yet available at the moment of the loading.
    There is someone that can help me?

    Thanks.

  16. Fabio says:

    I resolve my problem just with a further reading of the article! I used IE and it have some problem with abject element but only if the svg image is dynamic.

    Bye bye.

  17. Grey says:

    Just a word on conditional comments… “downlevel-revealed CCs” (Microsoft) are not valid markup… use a combination of them that hides them inside a real comment:


    This will not be seen by IE.

    Quick search reveals what I am referring to:
    http://pink.odahoda.de/blog/attic/2005/04/06/valid-downlevel-revealed-conditional-comment

  18. Grey says:

    The example (that was screwed up by comment system) should have been:

    <!–[if IE]><![if !IE]><![endif]–>
    <p>This will not be seen by IE.</p>
    <!–[if IE]><![endif]><![endif]–>

  19. Helder Magalhães says:

    Recently I’ve found a neat trick [1] which avoids using IE’s conditional comments. This allows saving a few extra bytes and also make the document more elegant.

    Regards,

    Helder Magalhães

    [1] http://joliclic.free.fr/html/object-tag/en/object-svg.html
    [2] http://my.opera.com/Andrew%20Gregory/blog/2007/08/04/svgs-on-web-pages

  20. pradeep says:

    Hello,

    Please help me with the following problem:

    Chrome complains with The documentView interface is not supported Non-W3C methods of obtaining “window” also failed When tried to run these cross-platform examples.
    https://jwatt.org/svg/demos/scripting-across-embed.html
    https://jwatt.org/svg/demos/scripting-across-object.html

    I remember I had used this a year back in my implementation and it worked fine with all the browsers including chrome. How it seems to complain.
    One of the module is heavily dependent on this piece of code. Please help me how to resolve the issue or work around for the same.

    I need to call the js functions inside the svg from external js.

    Thank you