Maintained by: David J. Birnbaum (djbpitt@gmail.com) Last modified: 2022-11-11T00:25:14+0000
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:
<img>
element<embed>
element<object>
element<iframe>
element<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.
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
, but, more precisely, a <p>
element<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.
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.
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:
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 right column of the bottom chart at http://ft.obdurodon.org/reports/balance1.xhtml. (This chart doesn’t happen to use SVG, but we’re looking at it now because of the layout, and not the underlying code.)
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. See our Viewbox tutorial for more information.
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—but don’t copy our JavaScript, which
is no longer consistent with Best Practice). 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.
windowin the XHTML (image scrolls horizontally within its
window, while the rest of the page doesn’t). This method is described in more detail below.
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 CSS like the following:
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.
For proper handling and validation of documents that embedded SVG inside HTML, you need to do the following:
<!DOCTYPE html>
.xhtmlinstead of
.html