In the last few years, a quiet revolution has been taking place in web browsers and operating systems. Solid implementations of SVG have become standard in both desktop and mobile browsers.
As this has happened, web developers and designers have become more confident in using SVG to display content that moves beyond HTML layout. They have also been combining SVG with the power of the newer, efficient and standardized JavaScript engines to build sophisticated information graphics and interactive games. Anyone working with data visualization on the web is now gaining familiarity with SVG as a tool.
The history of SVG has not been straightforward. As with HTML, CSS, and the other standards that make up the web, the development of SVG has been a process of back-and-forth compromises between the authors of specifications, the builders of web browsers that implement them, and the designers of web pages that use them. Unlike those other languages, however, the SVG specification did not develop slowly and incrementally—it was created fully formed, as an incredibly complex graphics language.
If you work with HTML and CSS web design, you will find many aspects of SVG familiar—and a few quite different. The SVG standard was built upon other web standards, most notably XML and CSS, and has a complex DOM that can be manipulated with JavaScript. In that way, it is very similar to HTML. But because the primary focus of SVG is graphics, not text, it intersects and connects the parts of the web platform that you usually try to keep separate: content, formatting, and functionality.
This chapter starts with a refresher about the main web languages and their separate roles. It then looks at how SVG interacts with these languages. We adapt the stoplight example from Chapter 1 to show how you can build on a simple SVG to create complete web pages.
The web platform—the foundation on which all web sites are built, from global forces like Google and Facebook to niche blogs and web apps—consists of a half-dozen core coding standards, and countless extensions of them. Each standard is a plank that connects the browsers (and other software) that interpret the web page code to the developers that write it. So long as both ends, browsers and developers, stay firmly attached to a common standard, the structure stays sound and web sites function as expected in any browser, on any operating system.
However, all of these components—standards, browsers, and web sites—are in constant flux, adding new features and building new structures. If a browser doesn’t quite reach the level of the standard a developer is using, something needs to be cobbled together to connect them, or the page ends up broken in appearance or function. In many ways, the web platform is more of a ramshackle raft than anything you would want to build a house upon. But somehow it all hangs together, most of the time.
If you are only interested in SVG as an image format—as a tool to create static, unchanging pictures—you don’t need to worry too much about the other web standards. To take full advantage of SVG as a graphical web application, however, you will need to leverage the entire web platform to build and extend your graphics. You’ll need to understand what each language adds to the web in general, and to SVG in particular.
Since the web standards movement first gained hold in the late 1990s, a key organizing principle—to help control the chaos—has been the separation of concerns. Different aspects of a web site or application should be kept in separate code blocks or files, in order to support the greatest flexibility and re-usability of code. Figure 2-1 visualizes how the main web languages each have their separate, but interconnected, concerns.
Each component has a clear role to play:
The language most strongly associated with the web is HTML, HyperText Markup Language. Hypertext meaning that the text in one document is connected to further information stored elsewhere; markup meaning that the structure is described by codes included in the main text. Not all information can be represented as HTML, whose markup tags are designed to describe text documents. The eXtensible Markup Language (XML) allows diverse data and document formats to be represented with a consistent syntax. Programs to edit, validate, and manipulate XML documents only needed to know the XML syntax rules, not the particulars of the document type. XML, while the basis of countless file types, has not—as initially planned—replaced the looser syntax of HTML; nonetheless, a document can be both HTML and XML compatible when required, a format known as XHTML.
Web pages may be written in HTML, but the web is connected with the Universal Resource Identifier system (URI, formerly Universal Resource Locators, URL) that identifies resources on the web, and the HyperText Transfer Protocol (HTTP) that transmits them from server to browser.
These standards overlap the HTML language in one area: links. The URI/URL addressing system identifies hyperlink destinations and embedded resources such as images. HTTP mostly operates behind the scenes, in the browser source codes. Front-end web page developers should at least be aware of the HTTP form-submission methods (GET and POST) for sending data to the server, and the HTTP header system for identifying files from the server and for sending user information (e.g., web cookies) with file requests.
Cascading Style Sheets (CSS) were developed as an alternative to the formatting-focused HTML tags that flourished in the early years of the web. CSS offered two main benefits: presentation information could be separated into style blocks or stylesheet files, and multiple stylesheets could be applied to a single document.
By separating the styles, one stylesheet could be used for many web pages on a site, and the HTML markup could focus on the content. By cascading style rules through multiple stylesheets, users could retain some control over appearance, by setting their own defaults and by marking certain features as !important
if, for example, poor eyesight makes large text or high-contrast colors essential.
The benefits of CSS were such that HTML 4.01 deprecated—discouraged the use of—formatting markup when it was finalized in 1999 by the World Wide Web Consortium (W3C). Web designers were, and are, advised to separate structure (HTML) from presentation (CSS) as much as possible, connecting the two only by the selectors in the CSS and the class attributes in the HTML. Ideally, it should be possible to completely change the style of a web page without altering the HTML.
Dynamic web pages, which could react to user actions in the same way desktop computer programs did, were another new feature developed by early web browsers trying to distinguish themselves. Netscape Navigator 2 was the first to include programming code, using JavaScript, a flexible, informal scripting language whose syntax was (very) loosely inspired by the then-dominant Java. Other browsers developed similar-but-different scripting rules.
While HTML and CSS were standardized by the World Wide Web Consortium (W3C), scripting was standardized by the organization ECMA International (formerly the European Computer Manufacturers Association) and is officially known as ECMAScript. This book will follow the terminology used by the vast majority of web developers, and call it JavaScript. Thankfully, most browsers now support the ECMAScript standards, so the distinction is no longer relevant.
ECMAScript only provides half of the functionality required for dynamic HTML. It defines basic data types, functions, and control structures. It doesn’t define how the parts of a web page work. The Document Object Model (DOM) connects JavaScript to HTML/XML. It defines a web document, not as a stream of text with formatting marks, but as a collection of data objects. The DOM specifications define how these objects are nested within one another, along with their properties and methods. Unlike JavaScript, the DOM was defined via the W3C, originally with the intent it could be implemented in any programming language. There is also a CSS object model (CSS OM) that allows scripts to manipulate the rules in a stylesheet.
Web page scripts can also use HTTP to access other files or database gateways on the Internet. Commonly known as AJAX, for Asynchronous JavaScript And XML, the technique relies on the XMLHttpRequest
API, first introduced as an add-on to Internet Explorer but now widely supported and being standardized.1 Although initially intended for accessing XML data files, it can import any information accessible via HTTP, and can manipulate the HTTP headers sent with the request.
The web exists at the intersection of these components (in the starred regions of Figure 2-1). Individual web pages are built from HTML/XML, CSS, and Javascript. Complex web sites are held together by hyperlinks, AJAX, URIs and HTTP.
Where does SVG fit on the web platform? SVG is an XML langauge, describing a structured document. However, because SVG is a graphics format, the structure of the document cannot be separated from its visual presentation. SVG elements represent geometric shapes, text, and embedded images that will be displayed on screen according to a clearly defined geometric layout. Other markup defines complex artistic effects to be applied to the graphical elements.
SVG exists because not all documents can be displayed with HTML and CSS. Sometimes content and layout are inseparable. In charts and diagrams, the position of text conveys its meaning as much as the words it contains. Other meaning is conveyed by symbols, colors, and shapes—without any words at all. Any complete representation of the content of these documents includes the layout and graphical features.
The same could be said about any image, and images have been part of web pages since the early days of HTML. The W3C even standardized an image format (Portable Network Graphics, PNG) that encodes icons and diagrams in compact files and can be used royalty-free by any software or developer.
The difference is that all other image formats on the web are displayed as single, complete entities. SVG, as an XML document, has structured content with a corresponding DOM. Stylesheets and scripts can access and modify the components of the graphic. Search engines and assistive technologies can read text labels and metadata.
SVG on the web can be used as independent files, with hyperlinks to other files and JavaScript-based interaction. However, SVG was not designed to display large blocks of text. Nor does it include form-input elements or other specialized features of HTML. The most effective use of SVG is therefore not as a replacement for HTML, but as a complement to it. SVG web applications are nearly always presented as part of larger HTML web pages, either as embedded objects or—with increasing frequency—directly included inline within the HTML markup.
As SVG has been integrated into web pages, the web pages themselves have changed. The HTML 5 specification and the many CSS Level 3 (and beyond!) specifications have significantly changed the relationship between SVG and the rest of the web platform. The dramatically improved performance of JavaScript since 2009 and the rise of JavaScript-based SVG libraries, such as Snap.svg and D3.js, are smoothing away many of the rough edges between implementations.
This book uses the terms HTML 5 and CSS 3 fairly generically. One of the main references for HTML, the WHATWG Living Standard, doesn’t use any version numbers; the competing spec at W3C is progressing through version numbers 5.1 to 5.2. These incremental changes can all be thought of as HTML 5+.
On the CSS side, the Level 3 and 4 specifications of existing features are being developed in sync with Level 1 and 2 specifications for new features. All of these (essentially, anything beyond the old CSS 2.1 specification) can be thought of as CSS 3+.
Nonetheless, when working with SVG in the browser, one must always be aware that implementations of the SVG standards are imperfect, incomplete, and frequently changing. This becomes all the more important when taking advantage of the features of HTML 5 and CSS 3 that directly integrate SVG. Cross-browser compatibility is an issue not only as it relates to support of the SVG standard, but also as it relates to support for new features in HTML, CSS, DOM, and JavaScript.
At the time of writing, the best supported version of SVG is 1.1; this specification was created in 2005, without adding any major new features to the original SVG standard. A proposed SVG 2 standard was published in September 2016. It adds many commonly requested features, clarifies numerous details, and improves coordination with HTML and CSS. Other more advanced SVG features are being proposed through additional modules.
There have been other SVG efforts, but these have not had a significant impact on the web. The draft SVG 1.2 standard was ambitious, adding features that would put it in line to replace Microsoft Powerpoint, as well as advanced vector manipulation of graphics. It was abandoned as unworkable when it became clear that the future of SVG would be in the browsers, not specialized software.
A simplified standard, SVG Tiny, was developed for mobile devices. The SVG Tiny 1.2 standard was finalized, with some new features from the main SVG 1.2 proposal; however, it fell out of favour as mobile browsers shifted towards displaying standard web pages.
The other web platform languages have also been revised, in parallel to the SVG work. Figure 2-2 sketches out a rough timeline of the past quarter-century of web standards. At the time SVG 1.1 was finalized, the established standards in other areas of the web included CSS level 2, DOM level 2, and ECMAScript (ES) level 3. Many SVG-centric tools, such as Apache Batik and libRSVG, have not significantly updated their CSS implementations since then, nor (in the case of Batik) their DOM and JavaScript implementations. In contrast, as of SVG 2’s publication, the latest web browsers all support DOM level 3 (and much of DOM 5) and ES 5.1 (and some ES 6), as well as at least some CSS 3+ features. And more features are added with every browser update.
This book focuses on SVG in the web browser, and it will often take advantage of the new features from other web specifications. However, many older web browsers and other software are still in use. We will identify areas where you’re likely to stumble across backwards-compatibility issues, and suggest workaround or fallback options.
This book is also very aware of the fact that SVG is still developing. New CSS modules are extending SVG functionality, and SVG 2 introduces a variety of changes. Throughout the book we will highlight these proposed features which, while not quite ready for production work, are useful to keep in mind as you learn the language. A graphic that is difficult to create now may be much easier with a new tool. The possibilities will be highlighted with “Focus on the Future” side bars like the following:
While there is still some inconsistency between the various SVG implementations, most browsers now have sufficient support for static scalable vector graphics and JavaScript-based dynamic content that it is possible to build complete graphical web applications with SVG.
If you’ve used JavaScript to create a dynamic HTML page, you can use it to create dynamic SVG. SVG elements inherit all the core DOM methods to get and set attributes and styles.
Of course, there are a few complications: SVG is a namespaced XML language, so you’ll need to use the namespace-sensitive DOM methods when creating elements or setting xlink
attributes. Also be aware that some methods you may be familiar with from HTML are not part of the core DOM specifications, such as the .innerHTML()
method to parse a string of markup or the .focus()
method to control keyboard focus. (Focus and blur control have been added to SVG 2, but aren’t universally implemented yet.) Even worse, some features such as .className
look similar but are structured differently.
As a sort of consolation prize for the missing HTML DOM methods, the SVG specifications introduced a variety of SVG-specific methods and properties to make graphical calculations easier. Unfortunately, many of these features were not universally implemented, and some have become obsolete as SVG switches to an animation model more compatible with CSS. Nonetheless, there are still a few useful features that can be relied on in most web browsers.
To include a script within a stand-alone SVG file, you can include a <script>
element anywhere between the opening and closing <svg>
tags. To include an external JavaScript file, use an xlink:href
attribute (not src
like in HTML) to give the file location. If you instead include the script in between the <script>
tags, remember to wrap it in an XML character data block, so that less-than and greater-than operators do not cause XML validation errors.
You can specify the scripting language using the type
attribute on individual <script>
elements, or the contentScriptType
attribute on the <svg>
element. However, it really isn’t necessary; the default type, application/ecmascript
(standard JavaScript) is the only type currently supported in most web browsers.
Most browsers—though not necessarily other tools—will also recognize the types application/javascript
and text/javascript
as synonyms. But avoid confusion by relying on the default.
We’ve already alluded to one common use of scripted SVG: cross-browser animation support. Example 2-1 shows JavaScript that could be used to replace the CSS animation from Example 1-6 or Example 1-7 from Chapter 1. The code uses classes to select the elements, so works with either the simple or labelled SVG markup: just remember to remove the CSS animation code from the <style>
element! The JavaScript should be inclued at the end of the file (right before the closing </svg>
tag), inside a <script><![CDATA[ /* script goes here */ ]]></script>
block.
(
function
(
)
{
var
lights
=
[
"green"
,
"yellow"
,
"red"
]
;
var
nLights
=
lights
.
length
;
var
lit
=
2
;
function
cycle
(
)
{
lit
=
(
lit
+
1
)
%
nLights
;
var
litElement
,
selector
;
for
(
var
i
=
0
;
i
<
nLights
;
i
++
)
{
selector
=
"."
+
lights
[
i
]
+
" .lit"
;
litElement
=
document
.
querySelector
(
selector
)
;
litElement
.
style
.
setProperty
(
"visibility"
,
(
i
==
lit
)
?
"visible"
:
"hidden"
,
null
)
;
}
}
cycle
(
)
setInterval
(
cycle
,
3000
)
;
}
)
(
)
The code is contained in an anonymous function, which creates a closure to encapsulate variables. Although not required, this is good coding practice to avoid conflicts between different scripts on a page.
The lights
array holds the class names that distinguish each light group. Since the number of lights won’t be changing, we can store it in a variable as well.
The red light is initially lit in the markup; this corresponds to index 2 in the lights
array; JavaScript array indices start at 0 for the first element.
The cycle()
function will change the lights.
To start the cycle, the lit
variable is advanced by one; the modulus operator (%
) ensures that it cycles back to 0 when it reaches the length of the array.
At each stage of the cycle, each color of light will be modified to either hide or show the “lit” graphic.
The “lit” <use>
element for each color is retrieved using the querySelector()
method; a CSS selector of the form “.red .lit” will select the first element of class “lit” that is a child of an element with class “red”.
The display style property is set to either block
or none
according to whether this light should be lit. Modifying the style property sets an inline style, which over-rides the presentation attribute in the markup.
The cycle function is run once to turn the light green, and then is called at regular intervals on a 3-second (3000ms) timer.
The anonymous function is run immediately: the syntax (function(){ /*...*/ })()
parses and runs the encapsulated code.
Although this isn’t a full web application—there is no interaction with the user—it demonstrates how SVG elements can be accessed and modified from a script.
There’s nothing SVG-specific about the JavaScript code: it selects elements using CSS selectors and the document.querySelector()
method, and sets the visibility
style according to which lit bulb should be displaying. A timer runs the cycle again after every three-second interval.
The querySelector()
method and its sibling querySelectorAll()
are convenient ways to locate elements using a combination of tag names, class names, and relationships to other elements. However, versions of Webkit and Blink browsers prior to mid-2015 had a bug that prevented them from working for SVG mixed case tag and attribute names, such as linearGradient
or viewBox
in HTML documents. To improve backwards compatibility, use classes on these elements if you need to select them in your code.
JavaScript and SVG can do more than re-create simple animations, of course. Scripts can be used to implement complex logic and user interaction. They are also useful for calculating the coordinates of shapes in geometric designs and data visualizations. You could even use JavaScript to implement your own form-input elements or wrapped-text blocks in SVG. But it’s generally easier to use HTML for that.
The stoplight graphic now cycles through green, yellow, and red lights when you view it in any modern web browser, and even in Internet Explorer 9 (the earliest IE to have SVG support). However, you won’t get any animation, in any browser, if you reference the SVG from the src
attribute of an HTML <img>
element!
It’s an extra complication when dealing with SVG in web pages: the behavior of SVG on the web can be quite different, depending on how the SVG is incorporated in the page.
If you’re using SVG on the web you’ll usually want to integrate the graphics within larger HTML files. There are a number of different ways that SVG can be added to web pages, each of which has advantages and disadvantages.
The most straightforward method is to use a self-contained SVG file as an image, and include it with the HTML <img>
tag. Example 2-2 provides the code for a super-simple web page using the CSS-animated SVG stoplight from Example 1-6. Figure 2-3 shows the result.
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"utf-8"
>
<title>
SVG Images within HTML</title>
<style>
html
,
body
{
background-color
:
lightYellow
;
margin
:
0
;
padding
:
0
;
min-height
:
100%
;
}
header
{
height
:
10em
;
background
:
#444
;
font-family
:
serif
;
}
header
h1
{
margin-top
:
0
;
color
:
red
;
text-shadow
:
yellow
0
0
4px
,
orange
0
0
2px
;
font-size
:
400%
;
}
header
img
{
height
:
8em
;
float
:
left
;
margin
:
1em
2em
;
}
p
{
padding
:
0.5em
;
}
</style>
</head>
<body>
<header>
<img
src=
"../ch01-overview-files/animated-stoplight-css.svg"
/>
<h1>
Tony’s Towing</h1>
</header>
<main>
<p>
Main text goes here, but<em>
WOW</em>
look at that image in the header!</p>
</main>
</body>
</html>
There are a couple features to emphasize in this example. First, note that the height of the image is being set in em-units, versus the height of 320px that was set in the SVG file ([Link to Come]). Just like other image types, the SVG can be scaled to fit. Unlike other image types, the image will be drawn at whatever resolution is needed to fill the given size. The width of the image isn’t set in Example 2-2; since both height and width were set in the SVG file, the image will scale in proportion to the height.
Or at least, that’s how it usually works. Internet Explorer scales the width of the image area in proportion to the height you set, but doesn’t scale the actual drawing to fit into that area. There’s an easy solution, however; it involves the viewBox
attribute that we’ll discuss in [Link to Come].
The second thing to note is that this is the animated SVG that is embedded. Declarative animation, including CSS animation and SVG/SMIL animation elements, runs as normal within SVG used as images—in browsers that support that animation type at all.
Or at least, that’s how it is supposed to work. At the time of writing (late 2016), MS Edge will not animate the SVG when it is embedded as an image in a web page, even though it supports CSS animation elsewhere. The same problem exists in Firefox browsers prior to version 51 (stable release at the end of 2016), even though the same versions support CSS animation in regular files and SMIL-style animation elements in images!
Why not use the scripted SVG animation from Example 2-1, which has better browser support? Because scripts do not run within images. That’s not a bug, it’s defined in the HTML spec: for security and performance reasons, files loaded as images can’t have scripted content.
There are some other important limitations of SVG used as images:
SVG in images won’t load external files (such as external stylesheets or embedded photos).
SVG in images won’t receive user interaction events (such as mouse clicks or hover movements).
SVG in images can’t be modified by the parent web page’s scripts or styles.
The limitations are the same if you reference an SVG image from within CSS, as a background image or other decorative graphic (an embedding option we’ll discuss more thoroughtly in Chapter 3).
If you want to use an external SVG file without (most of) the limitations of images, you can use an embedded <object>
, replacing the <img>
tag from Example 2-2 with the following:
<object
data=
"animated-stoplight-scripted.svg"
type=
"image/svg+xml"
>
</object>
You could also use an <embed>
element or <iframe>
with the same effect, although different support in older browsers. However, if you use an <iframe>
it will never automatically scale to match the proportions of your drawing. Objects will scale, but only according to the viewBox
attribute (which we haven’t gotten to yet), but not when the SVG dimensions have been defined using height and width (as in these examples).
Embedded objects can load external files, run scripts, and (with a little extra work and some security restrictions) use those scripts to interact with the main document. However, they are still separate documents, and they have separate stylesheets.
While embedded objects should be interactive and accesible parts of the main web page, just like <iframe>
-embedded documents in HTML, they can be a little buggy in browsers. Test carefully, including keyboard interaction and screen reader exposure, if you’re embedding interactive SVG as an <object>
.
Perhaps the biggest step towards establishing SVG as the vector graphics language for the web came from the W3C’s HTML 5 working group. When SVG was first proposed, as an XML language, it was expected that SVG content would be inserted directly into other XML documents, including XHTML, using XML namespaces to indicate the switch in content type. But most web authors weren’t interested in adopting the stricter syntax of XML when browsers rendered their HTML just fine.
With HTML developing separately from XML, it could have easily left SVG behind as another too-complicated coding language. Instead, the HTML 5 standard welcomed the idea of SVG content mixed in with HTML markup, just without the need for XML namespaces.
By making SVG a de facto extension of HTML, the HTML 5 working group acknowledged that SVG was a fundamental part of the future of the web. This has had—and will continue to have—a huge impact on SVG.
HTML 5 also introduced a number of features to further separate the structure of a document from its presentation, by making it easier to completely define the web page structure in the markup (or in the DOM, for dynamic pages):
new elements to describe the structure of complex web sites that consist of more than a single flow of information
new form input types to capture different types of data
adoption of the Web Accessibility Initiative’s Accessible Rich Internet Applications (ARIA) attributes, which allow authors to identify the structure and function of custom content
new elements and attributes to better support mixed-language content or content from languages that aren’t written as a single string of characters
The examples in this book will touch on some of these features but won’t go into too much detail; there are plenty of great resources on using HTML 5 out there. For using SVG, the most important thing to know about HTML 5 is the <svg>
element.
The HTML 5 <svg>
element represents an SVG graphic to be included in the document. Unlike other ways of embedding SVG in web pages, the graphic isn’t contained in a separate file; instead, the SVG content is included directly within the HTML file, as child content of the <svg>
element.
It’s also possible to include HTML elements as children of SVG content, using the SVG <foreignObject>
element. It creates a layout box in which an HTML document fragment can be displayed.
The <foreignObject>
was never supported in Internet Explorer, although it is available in Microsoft Edge. Foreign objects in SVG are somewhat quirky in most web browsers, and are best used only for small amounts of content.
There are some key differences to keep in mind between using SVG code in HTML 5 documents versus using it in stand-alone SVG files.
The most common area of difficulty is XML namespaces. The HTML parser ignores them.
If a web page is sent to the browser as an HTML file, namespace declarations have no effect. Namespace prefixes will be interpretted as part of the element or attribute name they preceed (except for a few attributes like xlink:href
and xml:lang
, which are hard-coded into the parser). If the webpage is sent to the browser as an XHTML file, or if the same markup is used in other XML content, the document object model that results may be different.
This book will try to use the most universally compatible syntax for SVG, and to identify any areas where you’re likely to have problems.
To further confuse matters, the DOM is sensitive to namespaces. If you are dynamically creating SVG, you need to be aware of XML namespaces regardless of whether or not you’re working inside an HTML 5 document.
Another important feature of SVG in HTML 5 is that the <svg>
element has a dual purpose: it is the parent element of the SVG graphic, but it also describes the box within the web page where that graphic should be inserted. The box can be positioned and styled using CSS, the same as you would an <img>
or <object>
referencing an external SVG file.
By including SVG content within your primary HTML file, scripts can manipulate both HTML and SVG content as one cohesive document. CSS styles inherit from HTML parent elements to SVG children. Among other benefits, this means that you can use dynamic CSS pseudoclass selectors—such as :hover
or :checked
—on HTML elements to control the appearance of child or sibling SVG content.
Example 2-3 uses HTML 5 form validation and the :valid
and :invalid
psuedoclasses to turn the an inline SVG version of the stoplight graphic into a warning light. If any of the user’s entries in the form are invalid, the stoplight will display red. If the form is valid and ready to submit, the light will be green. And finally, if the browser doesn’t support these pseudoclasses, the light will stay yellow regardless of what the user types.
<!DOCTYPE html>
<html
lang=
"en"
>
<head
>
<meta
charset=
"utf-8"
>
<title
>
Inline SVG within HTML
</title>
<link
rel=
"stylesheet"
type=
"text/css"
href=
"svg-inline-styles.css"
>
</head>
<body
>
<form
id=
"contactForm"
method=
"post"
>
<h1
>
How can we contact you?
</h1>
<svg
viewBox=
"20 20 140 320"
width=
"140"
height=
"320"
preserveAspectRatio=
"xMinYMin meet"
>
<defs
>
<circle
id=
"light"
cx=
"70"
r=
"30"
/>
</defs>
<rect
x=
"20"
y=
"20"
width=
"100"
height=
"280"
fill=
"url(gradients.svg#metal) silver"
stroke=
"black"
stroke-width=
"3"
/>
<g
stroke=
"black"
stroke-width=
"2"
>
<g
class=
"red light"
>
<use
xlink:href=
"#light"
y=
"80"
fill=
"url(gradients.svg#red-light-off) maroon"
/>
<use
class=
"lit"
xlink:href=
"#light"
y=
"80"
visibility=
"hidden"
fill=
"url(gradients.svg#red-light-on) red"
>
<title
>
STOP,
the form is incomplete or there is an error
</title>
</use>
</g>
<g
class=
"yellow light"
>
<use
xlink:href=
"#light"
y=
"160"
fill=
"url(gradients.svg#yellow-light-off) #705008"
/>
<use
class=
"lit"
xlink:href=
"#light"
y=
"160"
fill=
"url(gradients.svg#yellow-light-on) yellow"
/>
</g>
<g
class=
"green light"
>
<use
xlink:href=
"#light"
y=
"240"
fill=
"url(gradients.svg#green-light-off) #002804"
/>
<use
class=
"lit"
xlink:href=
"#light"
y=
"240"
visibility=
"hidden"
fill=
"url(gradients.svg#green-light-on) lime"
>
<title
>
GO, your information is ready to submit
</title>
</use>
</g>
</g>
</svg>
<label
>
<input
type=
"text"
name=
"CustomerName"
required
/>
Full Name
<abbr
title=
"Required"
>
*
</abbr>
</label>
<label
>
<input
type=
"email"
name=
"CustomerEmail"
required
/>
Email Address
<abbr
title=
"Required"
>
*
</abbr>
</label>
<label
>
<input
type=
"tel"
name=
"CustomerTelephone"
pattern=
"\s*\(?\d{3}\)?[-\s]*\d{3}[-\s]*\d{4}\s*"
title=
"10-digit number including North American area code. (Optional—Leave empty to be contacted by email only.)"
/>
Telephone Number
</label>
<button
type=
"submit"
>
Send
</button>
</form>
</body>
</html>
The DOCTYPE
declaration tells the browser to use the latest HTML standards when reading the file.
A linked stylesheet contains the CSS for both the HTML form content and the inline SVG.
The body of the web page contains a single <form>
element. It holds both the form input elements and the SVG that will give feedback about the user’s entries.
The root <svg>
element is included as a direct child of <form>
, and then contains all the graphical markup (as normal). For a pure HTML document, no namespaces are required (for XHTML, they would be); the HTML 5 parser knows to switch to SVG mode when it reaches an opening <svg>
tag. The width and height attributes provide default sizes; however, the final size of the SVG will be controlled by CSS. Two new attributes (viewBox
and preserveAspectRatio
) control the scaling of the graphic.2
The fill
values of each shape refer to gradients defined in a separate file, gradients.svg; the fill value also includes a solid color fallback value.3
This version of the stoplight graphic doesn’t include the <text>
labels, but it does include <title>
values, which will show up as tooltips, and should also be available to screen readers.4
Within the <body>
of the HTML page, a single form element contains a heading and then a modified version of the stoplight SVG code from Example 1-4. The first change is the addition of viewBox
and preserveAspectRatio
attributes to the <svg>
element. We’ll discuss these in detail in [Link to Come]; for now, just trust that these are the magic that make the SVG drawing scale to fit the dimensions we give it within the HTML page. The particular settings also ensure that the graphic will be drawn flush against the top left edges of the SVG area, making it line up neatly with the heading text.
Inside the SVG, the main change is that we’ve removed all the gradient definitions and put them in a separate file. As mentioned in Chapter 1, many browsers do not support this; it’s used here to shorten the code. In [Link to Come] we’ll discuss how scripting can be used to avoid this limitation by importing SVG content from another file; here, we use the SVG option of defining fallback colors as an alternative to paint servers. If the gradients cannot be accessed, the shapes will be filled with the solid colors instead.
The graphic doesn’t include animation label text. However, <title>
elements have been added to the illuminated versions of the red and green lights to clarify the meaning of the graphic. Each title will be available as a tooltip and as screen-reader accessible text when the corresponding “lit” shape is displayed. Since the yellow light is only displayed when we don’t have any information for the user, it hasn’t been given a title.
The rest of the code describes the form itself. Various HTML 5 form validation attributes have been used that will trigger invalid states:
The first two fields are required
, and so will be invalid when empty.
The second field is of type="email"
; browsers that recognize this type will mark it as invalid unless the content meets the standard format of an email address.
The third field is of type="tel"
, representing a telephone number. On its own, that doesn’t define a specific format, but the field also has a pattern
attribute that will only accept numbers in the format used in the United States and Canada. The format is expressed as a JavaScript regular expression; it requires groups of 3, 3, and 4 digits, optionally separated by whitespace or common punctuation. An HTML title
attribute is used to provide a tooltip with guidance to the user.
The :valid
and :invalid
pseudoclass selectors are supported on <form>
elements (as opposed to individual <input>
elements) in Firefox (versions 13+) and Blink browsers (Chrome and Opera, since early 2015). All other browsers currently display the indeterminate yellow light.
For more universal browser support, you could use a script to listen for changes in focus between input elements, and set regular CSS classes on the <form>
element based on whether any of the input elements are in the invalid state. The stylesheet would also need to be modified so that these classes also control the SVG styles.
Since this isn’t a book about JavaScript, we’re not going to write out that script in detail. Once again, nothing about the script would be SVG-specific. The SVG effects are controlled entirely by the (pseudo-)classes on the parent <form>
.
The styles that control the appearance of both the form and the SVG are in a separate file, linked from within the HTML <head>
. Example 2-4 presents the CSS code that controls the interaction.
@charset
"UTF-8"
;
/* Form styles */
form
{
display
:
block
;
margin
:
1em
;
padding
:
1em
;
background
:
lightyellow
;
border
:
double
navy
thick
;
border-radius
:
1em
;
overflow
:
auto
;
color
:
#002
;
}
label
{
display
:
block
;
clear
:
right
;
padding
:
0
0
1.5em
;
font-family
:
sans-serif
;
}
input
,
button
{
display
:
block
;
float
:
right
;
min-width
:
6em
;
max-width
:
70%
;
border-width
:
3px
;
padding
:
0.2em
;
}
input
:invalid
{
border-color
:
red
;
box-shadow
:
none
;
/* override browser defaults */
}
abbr
[
title
=
"Required"
]
{
color
:
red
;
font-weight
:
bold
;
text-decoration
:
none
;
border
:
none
;
}
form
:invalid
button
[
type
=
"submit"
]
{
color
:
gray
;
}
/* SVG styles */
form
svg
{
float
:
left
;
width
:
6em
;
height
:
14em
;
max-width
:
25%
;
max-height
:
80vh
;
overflow
:
visible
;
padding
:
1em
;
/* hack for browsers that don't */
margin
:
-1em
;
/* support overflow on SVG */
}
.lit
{
/* Set the lights off to start */
visibility
:
hidden
;
}
form
.yellow
.lit
{
/* By default (if HTML 5 form validation is not supported)
the yellow light will display */
visibility
:
visible
;
}
form
:valid
.green
.lit
{
/* If the validator thinks all form elements are ok,
the green light will display */
visibility
:
visible
;
}
form
:invalid
.red
.lit
{
/* If the validator detects a problem in the form,
the red light will display */
visibility
:
visible
;
}
form
:valid
.yellow
.lit
,
form
:invalid
.yellow
.lit
{
/* If either validator class is recognized,
turn off the yellow light */
visibility
:
hidden
;
}
The first batch of style rules define the appearance of the HTML form elements, including using the :invalid
selector to style individual inputs that cannot be submitted as-is. The <svg>
element itself is then styled as a floated box with a standard width and height that will shrink on small screens. The overflow
is set to visible to prevent the strokes of the rectangle from being clipped, now that the rectangle has been moved flush against the edge of the SVG. Older Webkit/Blink browsers only support SVG overflow onto the padding region, so padding is added and then cancelled out with a negative margin.
The remaining rules control the light behaviour. The .lit
versions of each light are hidden to start, then the yellow light in particular is revealed. If the form matches the :valid
selector, the bright green light is revealed; if it matches :invalid
, the bright red light is displayed. Finally, if either of those selectors is recognized by the browser, the illuminated version of the yellow light is hidden again.
Figure 2-4 shows the web page in action: when the form is empty (and invalid because of missing required fields), after the required fields are complete (and the form is valid), when there is a formatting error in a field (invalid), and when it is complete (and green light once again). The screenshots are from Firefox, which at the time of writing is the only browser that supports both the new pseudoclasses and SVG gradients from external files.
This demo uses familiar CSS approaches (classes and pseudoclasses) to style SVG in a dynamic way. But this is only the beginning of how SVG and CSS can be integrated.
CSS has also advanced considerably since SVG 1.1 was introduced. First, the core CSS specification was updated to version 2.1; work on that was finalized in 2011. At that time, work was already progressing on a variety of CSS modules, each focusing on specific topics and collectively known as CSS Level 3. There is no single CSS 3 specification, although the W3C CSS working group did publish a “snapshot” defining the current state of stable CSS recommendations.
As of the 2010 CSS snapshot, CSS included
basic document layout and text formatting features
an expanded set of selectors to target specific elements based on their position within the document or the state of form input elements
support for XML namespaces
expanded options for defining colors, including semi-transparent colors
the ability to selectively apply certain style rules by querying the size, orientation, color support, or other features of the display media
These features are widely implemented in web browsers, and can usually be used without problem when designing SVG for the web. SVG tools that still rely exclusively on the SVG 1.1 specifications should ignore the new style declarations.
An updated snapshot includes newer specifications, some of which are still not entirely stable. This includes many graphical effects, such as masking, filters, and transformations, that are direct extensions of features from SVG. These standards replace the corresponding SVG definitions (there are no equivalent chapters in SVG 2), allowing the same syntax to be used for all CSS-styled content. Support for these effects in browsers is more erratic; many bugs remain but they are slowly being squashed.
Chapter 3 goes into further detail about how CSS applies to SVG.
Not all aspects of CSS 3 have increased collaboration with SVG. Other new CSS features introduced similar-but-different graphical features that have put CSS in direct competition with SVG for some simple vector graphics. Whenever this book discusses a feature of SVG that has a CSS equivalent, we’ll highlight the similarities and differences using “CSS vs. SVG” notes like this:
CSS 3 also makes manipulating raster graphics easier. Multiple image files can be layered in an element’s background, and the images used or their positions can be adjusted according to properties of the display or states of user interaction. In many ways, working with raster images (using CSS or HTML) is more straightforward and predictable than using SVG. However, that predictability is also inflexibility, reflecting the fact that raster images are treated by the browser as a single unit with a predefined presentation.
The relationship between CSS and SVG is so complex, and so important, that we’ve given it a separate chapter. Chapter 3 will look at the ways CSS can be used to enhance SVG, and SVG can be used to enhance SVG. It will also consider the ways how CSS has started to replace SVG for simple graphics like the stoplight example we’ve been using so far.
This chapter aimed to provide a big picture of SVG on the web, considering both the role of SVG on the web and the way it can complement (and be complemented by) other web technologies.
The web is founded on the intersection of many different coding languages and standards, each with their own role to play. For the most part, web authors are encouraged to separate their web page code into the document text and structure (HTML), its styles and layout (CSS), and its logic and functionality (JavaScript).
SVG re-defines this division to support documents where layout and graphical appearance is a fundamental part of the structure and meaning. It provides a way to describe an image as a structured document, with distinct elements defined by their geometric presentation and layout, that can be styled with CSS and modified with JavaScript.
The SVG standard has developed in fits and starts. The practical use of SVG on the web is only just starting to achieve its potential. There are still countless quirks and areas of cross-browser incompatibility, which we’ll mention whenever possible in the rest of the book. Hopefully, the messy history of SVG and the inter-dependent web standards has reinforced the fact that the web, in general, is far from a perfect or complete system, and SVG on the web is still relatively new.
The goal of this book is to help you work with SVG on the web, focusing on the way SVG is currently supported in web browsers, rather than the way the language was originally defined. In many cases, this will include warnings about browser incompatibilities and suggestions of work-arounds. However, support for SVG may have changed by the time you read this, so open up your web browser(s) and test out anything you’re curious about.
1 The standard definition of XMLHttpeRequest
is at https://xhr.spec.whatwg.org/, managed by WHATWG, the Web Hypertext Application Technology Working Group, which is now also a key driver of HTML and DOM standardization.
2 See [Link to Come] for all about how viewBox
and preserveAspectRatio
interact.
3 See [Link to Come] for more on the complete fill syntax.
4 See [Link to Come] for more on how and why to use <title>
.