Using SVG on the Web
Monday, December 22nd, 2008If you are able to ignore Internet Explorer, all the other major browser can render SVG content. Recently, while writing previous posts and webapps, I discovered several quirks that may cause browsers to fail to render SVG content consistently.
Including SVG inline in the document.
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Using SVG inline in an XHTML document</title> </head> <body> <h1>Using SVG inline in an XHTML document</h1> <svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" style="border: 1px solid black"> <circle fill="rgb(250, 160, 20)" cx="100" cy="50" r="80" /> <rect fill="rgb(20, 250, 20)" fill-opacity="0.6" x="35" y="85" width="180" height="85" /> </svg> </body> </html>
View this example in your browser.
Inline SVG is an attractive option because it doesn’t require an external file. Unfortunately, inline SVG has one significant problem: authors are forced to use XHTML and the application/xhtml+xml
MIME type, instead of standard HTML and the text/html
MIME type. XHTML is not a very forgiving language, and one I would generally discourage. Depending on authoring tools and other content on the page, producing valid XML may be difficult. Even more problematic is that Internet Explorer will refuse to display the page at all; there is no graceful fallback for the majority browser. Finally, syndicating SVG in feeds will often cause the SVG to be stripped as it is syndicated.
I used inline SVG for my Mozilla compiler warnings front end, because I don’t care about Internet Explorer users in that application. But it has very limited usefulness in general.
Referencing external SVG content
At first glance, it might seem that you could reference an SVG document using the HTML <:img> element., but this is not the case. SVG images are complete sub-documents. They have their own script context and can script themselves. They can also load additional sub-documents such as images. Because of this, browsers force authors to embed SVG images using <object> or <iframe>.
Embedding SVG with <object>
The <object> element is the generic HTML mechanism for embedding external content. It can be used just like an <iframe> for external HTML document. It can be used to embed plugin-rendered content such as Flash, and it can be used to embed SVG:
<object type="image/svg+xml" data="http://benjamin.smedbergs.us/blog/wp-content/uploads/2008/12/svg-document1.svg" width="250" height="250"> Alternate markup here. If you see this, your browser may not support SVG, or a content aggregator may have stripped the object element. </object>
The object element is the best choice in most situations. All browsers including Internet Explorer will display the fallback content if they don’t know how to display SVG or if the image won’t load. Using the object element, authors can even pass parameters to the SVG document.
Embedding SVG with <iframe>
It is also possible to include SVG content using the <iframe> element.
<iframe width="350" height="250" src="http://benjamin.smedbergs.us/blog/wp-content/uploads/2008/12/svg-document1.svg"> Alternate markup here. If you see this, your browser might not support iframes, or a content aggregator might have stripped the iframe element. </iframe>
There are minor but important differences using iframe rather than object to display SVG: Internet explorer will load the iframe but choke on the SVG content. The user won’t skip back to the fallback content within the <iframe>element, and in some cases the user may see a download prompt for the SVG document. But many content sanitizers such as those found in feed aggregators will allow <iframe> through while rejecting <object> And finally, iframes have a border by default. You can remove this border using CSS.
Use this MIME type: image/svg+xml
The correct MIME type for SVG content is image/svg+xml
. Firefox will accept application/svg+xml
but Safari will not!
Specify image dimensions
The author should know the image dimensions in advance. If you don’t specify the width and height in the <object> or <iframe> element, browsers will initially size the object at 300×150 pixels, and then their behavior will diverge:
<object> | <iframe> | |
Firefox | Resize to the image intrinsic size, once loaded | Scroll overflow content |
Opera | ||
Safari | Crop overflow content | |
Example |
|
Don’t use rgba() colors in SVG
The CSS3 specification allows for any color to be specified with transparency using rgba syntax. Many web browsers support RGBA colors for HTML content, but only Firefox supports them for SVG content. Instead of using rgba colors, use the SVG properties fill-opacity
and stroke-opacity
for maximum portability.
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="100"> <circle fill="rgb(180, 180, 250)" cx="100" cy="20" r="85" /> <text x="10" y="45" font-size="40" fill="rgba(0, 0, 0, 0.3)">rgba transparent text?</text> <text x="10" y="95" font-size="40" fill="black" fill-opacity="0.3">use fill-opacity instead!</text> </svg>