Digital humanities


Maintained by: David J. Birnbaum (djbpitt@gmail.com) [Creative Commons BY-NC-SA 3.0 Unported License] Last modified: 2015-08-22T21:26:50+0000


Embedding SVG in XHTML

Mixing SVG and XHTML

HTML has always provided an <img> element for embedding image files in web pages, and initially the only image formats supported in web browsers were static bitmapped images, such as GIF, JPG, and PNG. These formats remain convenient for images that are fundamentally pictorial, such as photographs, but images with textual implications, such as charts and graphs, are more appropriately rendered in SVG. Not only does the SVG vector format mean that the image retains its crispness at any magnification or resolution (which is not the case with bitmapped files), but it also makes it possible to use DHTML to manipulate the display in response to user-generated events. For example, with SVG graphics the user can use DHTML (a combination of JavaScript and CSS) to do any of the following (all implemented in http://zatochnik.obdurodon.org):

This sort of interoperability between the XHTML and SVG portions of a page are possible because the browser builds a single tree representation of the composite document. CSS and JavaScript then operate on that tree, without caring whether a part of that representation is XHTML or SVG. They address any node in the tree the same way, which means that an event in one part of the page can affect objects in another part of the page.

Bitmapped images do support user interaction through image maps (the HTML <map> element), but the fact that an SVG image is, at a structural level, XML, makes the integration of SVG with XHTML much more powerful than is the case with bitmapped image formats.

There are at least five common ways of incorporating SVG into XHTML:

  1. The HTML <img> element
  2. The HTML <embed> element
  3. The HTML <object> element
  4. The HTML <iframe> element
  5. In-line SVG, that is, inserting an <svg> element directly into the XHTML.

The last of these approaches, in-line SVG, is generally considered Best Practice, and it is the only one we use in our own projects. It is supported in all major modern browsers, but not in older ones, so if your priorities include support for legacy browsers, you’ll need to use one of the other methods. We describe how to use in-line SVG below.

Remember namespaces?

XHTML and SVG are both XML, and both therefore support namespaces, a technology where the generic identifier (GI, the name of an element) carries with it, implicitly or explicitly, a namespace. That is, an XHTML <p> element is actually not just a <p> element, but, more precisely, a <p> element in the XHTML namespace. The same document could simultaneously contain a <p> element in some other namespace without risk of confusion; namespaces allow the reuse of the local name part of a generic identifier with different meanings in different namespaces.

More specifically for our purposes, XHTML with in-line SVG uses namespaces to ensure that the browser treats XHTML as XHTML and SVG as SVG without having to rely on an entire document (web page) being entirely in one of these vocabularies or the other. As long as every element in the document is associated with the appropriate namespace, the browser will know how to render it. In our document, every XHTML element is explicitly in the XHTML namespace and every SVG element is explicitly in the SVG namespace, and the browser thus knows how to render both parts, even within a single document.

Inserting in-line SVG into XHTML

For ease of management, we normally create a <div> in our XHTML and insert our SVG inside it. This isn’t strictly required, but it reflects the fact that our SVG is logically a discrete, integral part of the document, which is what a <div> is supposed to represent, and it makes it easier for us to implement certain types of styling, such as the horizontal scrolling defined below. We implement the actual insertion either by generating the SVG directly in place, or by generating it separately, in a stand-alone file, and then inserting that file into the XHTML document with a server-side include. With the second approach, the stand-alone SVG file cannot begin with an XML declaration (<?xml version="1.0" encoding="UTF-8"?>); you can suppress its appearance in the XSLT that outputs your SVG by using <xsl:output omit-xml-declaration="yes"/>. The stand-alone SVG also cannot contain a DOCTYPE declaration (the line at the top of some XML documents that begins <!DOCTYPE), but that normally isn't generated during an XSLT transformation unless you ask for it explicitly, so you shouldn’t have to worry about suppressing it.

When the SVG is too wide

SVG most often has a fixed size, typically expressed in the default unit of pixels, but you can control the dimensions in several ways. In most cases, you’ll calculate the width and height of your SVG when you generate it, and you can write those values into @width and @height attributes on the root <svg> element. For a small image that will fit comfortably on the page, that’s all you need to do, but larger images require special consideration. In our work, we usually don’t worry about the height of an image because users are accustomed to vertical scrolling, but if an image is sufficiently wide to require horizontal scrolling, there are at least four approaches available:

  1. Swap the horizontal and vertical dimensions (image scrolls vertically). We’re accustomed to bar charts that spread the bars from left to right, but if there too many bars to fit comfortably across a normal browser window and they don’t contain much information, it might be better to array them vertically. See, for example, the bottom chart at http://ft.obdurodon.org/balance1.php.

  2. Set the @viewBox (image resizes to fit the window, maintaining its original aspect ratio). The root <svg> element, in addition to specifying (optionally) width and height (as @width and @height attributes), supports a @viewBox attribute. If you add a @viewBox attribute that is coordinated with the values of the @width and @height attributes (e.g., <svg xmlns="http://www.w3.org/2000/svg" width="2000" height="500" viewBox="0 0 2000 500" preserveAspectRatio="xMinYMin meet">), the image will resize along with the browser window. You can override the default maintenance of the original aspect ratio, although typically you won’t want to. You can look up the @viewBox and @preserveAspectRatio attributes on line for more information.

  3. Use horizontal percentages instead of fixed values (image grows and shrinks horizontally, while maintaining a constant height). It is possible to specify horizontal positioning in percentage values, rather than in a fixed unit of measure, and those percentages will adjust themselves to the width of the window. For example, an object with an X coordinate of 50% will be anchored half-way across the screen regardless of the width of the screen. If all horizontal positions are specified in percentages, the entire image will swell and shrink as the user resizes the window. We use horizontal percentages in the SVG portion of http://zatochnik.obdurodon.org (you can view the source to see the values).

    If you use percentages for horizontal positioning, it is best to specify all horizontal positioning in percentages. Mixing absolute values and percentages can be confusing for the developer.

  4. Use CSS to make the SVG scroll horizontally within a window in the XHTML (image scrolls horizontally within its window, while the rest of the page doesn’t). This method is described in more detail below.

Scrolling the SVG horizontally in a window

Horizontal scrolling can be enabled for the contents of an XHTML <div> element by setting the CSS overflow-x property to scroll. To scroll SVG within XHTML, you need to nest it inside a <div> element, along the lines of (this example assumes an SVG image that is 500px in height and 2000px in width):

<div id="wrapper">
    <svg xmlns="http://www.w3.org/2000/svg" height="500">
    (SVG goes here)
    </svg>     
<div>

This code inside your XHTML document must be paired with the following CSS:

svg{
  width:2000px;
}
#wrapper{
  border:2px black solid;
  padding:0 1em;
  overflow-x:scroll;
}

The wrapper <div> adjusts its width in tandem with the window, which is the default behavior. The border and padding are optional. It is necessary to specify the width of the SVG image in the CSS (using the svg selector); this, combined with setting the overflow-x property to scroll under the #wrapper selector (the hash mark selects the element with the @id value wrapper, which is our wrapper <div>), will cause a horizontal scroll bar to appear at the bottom of the <div> whenever it is too narrow to accommodate its contents. Since we’ve declared the width of the SVG image as 2000px, the SVG will scroll inside the border of the <div> whenever the window is narrower than 2000 pixels.

You can see an example of this at http://dh.obdurodon.org/election.xhtml.

A note about validation

For proper handling and validation of documents that embedded SVG inside HTML, you need to do the following: