In building web pages it is often necessary to add some sort of button. What better way of doing so than with an SVG button? This tutorial guides you through drawing a simple SVG button and then adding some functionality to it.
The steps are:
Draw a simple button with 3D shading.
Use the button in an HTML page to access another web page.
Animate the button using SMIL.
Use JavaScript (ECMAScript) to create a two-state button with accessibility features.
Add CSS styling to the button.
![]() | SVG in HTML5 |
---|---|
Support for SVG in browsers has greatly improved in the past few years. However, there are still some inconsistencies between the browsers so cross-browser testing is vital. |
Procedure 1.8. Creating an SVG Button
Drawing a Button.
There are countless ways to draw buttons as one can see by searching for button images on the web. This example uses a rather simple style that allows the button color to be defined by a CSS style sheet. The button's color will be the color of a base rectangle. 3D effects will be added using semi-transparent overlays.
Set up the drawing.
With the Document Properties dialog
( → (
Shift+Ctrl+D
)), set the drawing size to
240 × 100 pixels. Create a Grid with spacing of 10
pixels and turn snapping nodes to the Grid on
(
in Snap Bar).
The default drawing templates in Inkscape include a Layer. This is a glorified SVG <g> (group) object marked by a special Inkscape specific attribute. Layers are useful in Inkscape for a variety of things such as quickly hiding or showing sets of objects. For this project, Layers are more a hinderance than a help. Remove the Layer by opening the Layer dialog ( → ( Shift+Ctrl+L )) and with the default layer highlighted, click the − button.
Draw the base rectangle.
Draw a rectangle 220 × 80 pixels centered on the page (upper-left corner at 10, 90 pixels). Drag the Corner Shape handle (circle at upper-right corner of rectangle) down as far as it will go to round the corners. Give the rectangle a red (or other color) Fill.
It is useful to change the id (the internal label) of the rectangle to “ButtonBase”. This will allow us to easily reference the rectangle to change its color via CSS style sheets or JavaScript.
The id of the rectangle can be changed using the Object Properties dialog ( → ( Shift+Ctrl+O )) or the XML Editor dialog ( → ( Shift+Ctrl+X )). We'll use the latter as we'll have one case later where the former won't work. Open the XML Editor dialog. Select the rectangle in drawing. The XML entry for the rectangle will be highlighted on the left side of the XML Editor dialog. The attributes for the rectangle are shown on the upper right. Click on the id attribute on the right. This selects the attribute for editing in the entry area on the lower right. Change the id value to “ButtonBase”. Either click the Set button or use Ctrl+Enter to finalize the change. While looking at the dialog, note that the corner radius ry is set to 40, half the height of the rectangle.
Add a highlight.
Now we'll add some 3D effects. First we'll add a reflection
off the top. First draw a rectangle with a size of 180
× 40 pixels and with the top 10 pixels below the top
of the base rectangle (upper-left corner at 30, 85
pixels). Change the Fill to white so that the rectangle
can be seen. Make sure that the Corner
Shape handle is half-way down the right side. If
you have trouble moving the handle, try resetting the
handle by clicking on the
icon in the
Tool Controls.
The next step is to convert the rectangle to a path
via
Shift+Ctrl+C
). Then, with the Node Tool,
select the path. The nodes should already be Auto-smooth
nodes. If not, select all the nodes and
convert them to
Auto-smooth
Nodes by clicking on the
Make selected nodes auto-smooth
(
) icon in the Tool Controls.
Next move the bottom two nodes up 15 pixels. Shorten
the bottom handes on the two side nodes to 5 pixels.
Use the Gradient Tool to add a Gradient to the
highlight. First select a linear Gradient by clicking
on the Create linear gradient
(
) icon in the Tool Controls.
Next, click-drag from the top of the base rectangle down to
its center. This should create a gradient that is solid at
the top and transparent at the bottom. If the colors are
not white, select the Gradient handles
and click on the white square in the Palette. Then
select just the bottom handle (a circle) and set the
opacity to zero by clicking with the Right
Mouse button on the Opacity
indicator (0:) in the Style Indicator. at the lower-left
corner of the Inkscape window and selecting
0 (transparent) from the pop-up menu.
Finally, with the XML Editor dialog, change the id of the path to “ButtonHighlight”.
Add a glow.
Now we'll make the button glow a little bit by adding a
rectangle with a radial gradient. The gradient will have a
transparent center and darken toward the edges. First,
select the base rectangle and duplicate it
(
Ctrl+D
)). Change the Fill to black. Now
use the Gradient Tool to create a Radial
Gradient by clicking on the
icon in the Tool Controls
and then click-dragging from the bottom center of the rectangle
upward. This creates a radial gradient that is black in
the center and transparent on the edges. Swap the center
and edge colors by using
Shift+R.
Set the opacity of the rectangle to 50% by selecting
50% in the menu that pops-up when
Right Mouse clicking on
the Opacity indicator (O:) at the
lower left of the Inkscape window. Stretch the gradient
by dragging the horizontal handle to
the left about 50 pixels past the left edge of the page. Move
the rectangle below the highlight by clicking on the
icon in the Tool Controls of the
Select Tool or using the shortcut Page
Down.
With the XML Editor dialog, change the id of the glow rectangle to “ButtonGlow”.
There are endless ways to enhance the visual effect of the button by adding shadows, more highlights, etc., but for the moment we'll stop here.
Add some text.
Add some text to the button using the Text Tool.
Choosing center-aligned text via the Align
center icon in the Tool Controls makes it
easier to keep text centered in the button. Click a bit
below the center of the rectangle to begin adding text.
Give the text a white fill. Change
the id of the
<tspan>
element to “Text”
with the XML Editor dialog. To access
the <tspan>
object, you may need to
click on the little triangle at the left of
the <text>
entry in the dialog.
To help with a 3D effect, a copy of the text with a black fill can be placed behind the original text and shifted down one pixel. The text can also be moved behind the highlight to make the text look like it is inside the button. If you have added a copy of the text, change the new <tspan> id to “TextShadow” with the XML Editor dialog.
Finally, save the button as button.svg
.
Use the button in an HTML web page.
In this step we'll use the button in an HTML web page. We'll first use the button as a static object as one would use a PNG button. The advantage of using an SVG button, of course, is that is scalable.
Here is a simple HTML5 web page to test our button (it uses
XHTML so save the file as test.xhtml
and
in the same directory as the SVG file):
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml">
<head> <meta charset="UTF-8"/>
<title>Sample use of an SVG Button</title> </head> <body> <h1>An SVG button</h1> <a href="http://tavmjong.org/INKSCAPE/"> <img src="button.svg" alt="A sample button."/>
</a> </body> </html>
HTML declaration. (With HTML5 no “dtd” is required.) | |
HTML Name Space declaration. The XML syntax is specified here. | |
The character encoding of the file
(normally | |
Inclusion of the SVG file via the |
The SVG button has been included via the
<img>
tag. Unfortunately, this tag does not
have a simple means of providing a PNG backup. The more
useful <object>
tag, which does have that
ability will not pass mouse pointer events from the SVG to
the HTML (i.e. to the <a>
tag) in most
browsers.
Animate the button using SMIL
The next step is to give our button a little pizazz. We'll do this via SMIL animation. We could also use JavaScript (ECMAScript) but SMIL animation has the advantages of being simpler and also working inside the <img> tag where scripting won't work. Unfortunately, SMIL animation is not be supported in Internet Explorer and Edge (SMIL also appears to be a bit of a resource hog).
You can do a lot of things with SMIL animation such as shifting or scaling parts of the button. We'll simply make the button “throb” by animating the “glow” rectangle. This will be done by varying the opacity of one of the Stops of the “glow” Gradient. To make the necessary changes, the SVG file must be edited using a text editor that can save the file as plain text.
Open the SVG button file in the text editor. Look for the
rectangle with the id
“ButtonGlow”. Note the name
(id) of the referenced gradient. This will
be the value of the “url” for
the “fill”. It will be something
like “radialGradient3165” (the '#' is not part of
the name). Now go to the <defs>
section
near the top of the file at find the radial gradient with the
same id. This “radialGradient”
will reference a “linearGradient” where the
Stops are defined. The name of
this “linearGradient” will be found in
the “xlink:href” line. Find
the “linearGradient” in
the <defs>
section.
Now that we have found where the Stops are defined, we can
edit the file. Find the Stop with the
stop-opacity value of '0'. Change this
“stop” from a self-closing tag to an opening
tag. That is change:
<stop ... />
to
<stop ... >
.
Next, add a “stop” closing tag:
</stop>
after the opening tag.
Then insert the following lines between the “stop”
opening tag and the “stop” closing tag:
<animate attributeName="stop-opacity" values="0;0.5;0" dur="2s" repeatCount="indefinite"/>
The “stop” should look something like this:
<stop id="stop3163" style="stop-color:#000000;stop-opacity:0" offset="0"> <animate attributeName="stop-opacity" values="0;0.5;0" dur="2s" repeatCount="indefinite"/> </stop>
The button should now slowly throb when viewed in a browser
that supports SMIL (not Inkscape!). The first part of the
<animate>
tag defines which attribute is being
animated; most attributes can be, although colors may need a
special <animateColor>
tag. The next part
gives a list of values that should be interpolated between. In
this case, stop-opacity begins with a
value of zero which is ramped up to 0.5 and then back down to
zero. The dur parameter gives the time the
animation should take to go through one cycle. The
repeatCount defines the number of times the
animation should be repeated, in this case indefinitely. There
are many more options but a full discussion of SMIL is
outside the scope of this book.
A two-state button with accessibility features.
We'll now modify the button to have two states. This will
necessitate using JavaScript (ECMAScript) which means that
the button will not work on a web page if embedded using the
<img>
tag. We'll keep track of the two
states by using the value of the attribute
aria-pressed. We could use any JavaScript
variable to keep track of the state but by using this attribute,
which is defined in the
WAI-ARIA
specification, the state of the button can be monitored by
accessibility programs such as screen readers.
The first step is to add a couple attributes to the opening
<svg>
tag. The first is the
role attribute. This attribute, necessary
for ARIA, defines the purpose of the SVG file. In this
case, the SVG is being used as a button so set the value
to “button”. The second attribute to add is
aria-pressed. This attribute, also
required by ARIA, can have the values: “true”,
“false”, or “mixed” (we'll use only
the first two). It keeps track of the button state. Set the
value to “false” to begin with.
<svg ... role="button" aria-pressed="false" ... />
Next, in the <g>
tag add the two attributes:
onkeydown and onclick
to specify actions to be taken when a user activates the
button. In both cases, the same JavaScript function,
buttonEvent(evt)
, is called. The
onkeydown attribute is not yet part of the SVG
standard but is supported by many browsers. It is required for
accessibility to allow a person to activate the button using the
keyboard. The attributes are added here rather than in the
<svg>
tag to ensure that the button is
active only when the mouse is over the visible parts of the
button (which are all contained inside the
<g>
tag).
<g id="layer1" onkeydown="return buttonEvent(evt);" onclick="return buttonEvent(evt);">
The final step is to add the JavaScript just after the
“defs” section (after </defs>
).
This is the script:
<script type="text/ecmascript">function buttonEvent(event) {
if ((event.type == "click" && event.button == 0) || (event.type == "keydown" && (event.keyCode == 32 || event.keyCode ==13))) {
var SVGDocument = event.target.ownerDocument;
var SVGRoot = SVGDocument.documentElement; var ButtonBase = SVGDocument.getElementById("ButtonBase"); var Text = SVGDocument.getElementById("Text"); var TextShadow = SVGDocument.getElementById("TextShadow"); var pressed = false;
var fill = "red"; var text = "OFF"; if ("false" == SVGRoot.getAttribute("aria-pressed")) {
pressed = true; fill = "green"; text = "ON"; } SVGRoot.setAttribute("aria-pressed", pressed);
ButtonBase.style.setProperty("fill", fill, ""); Text.firstChild.nodeValue = text;
TextShadow.firstChild.nodeValue = text; } } </script>
Start of script section. The “type” must be
declared as | |
Start of function called when the button is clicked (or when activated by a key press). A pointer to an “event” structure is passed to the function. | |
The event is checked to make sure it is of a type we are interested in. | |
References are obtained to the relevant SVG objects. | |
Initial variable values. They should match what is declared in the body of the SVG. (This is not the most optimal way to structure the SVG as the same values are defined twice. One could add an initiation function to set the values once.) | |
Variables are toggled if necessary. | |
The necessary attributes and properties are set. | |
The text is changed. Note that the text is stored in a
child node of the |
Our two state button is self-contained and would be useful, for
example, in turning on and off an animation inside the same
SVG file. To make it useful to control something external to
the SVG file one just needs to call a function in the parent
HTML document with the value of the current state. This is as
simple as adding top.status(text);
at the end of
the “buttonEvent” function,
where status
is a function defined in the parent
HTML. Inside the <head> section of the HTML add:
<script type="text/ecmascript"> function status(text) { document.getElementById("status").innerHTML = text; } </script>
And in the <body> of the HTML add something like:
<p>The button is <b id="status">OFF</b>.</p>
![]() | Note |
---|---|
This may not work locally due to cross-origin restrictions (CORS). |
If you would like to use the button several times on one web
page you'll need to know which button has been pressed. You can
find the id of the object that wraps the
SVG by adding var frameId =
window.frameElement.id;
in the script inside the SVG
file and then passing frameId
as an argument in
the call to the HTML funciton (i.e., top.status( text,
frameId );
).
CSS styling.
This section will demonstrate how to style SVG with both internal and external style sheets. This section provides only an introduction into style sheets. A full discussion of CSS is outside the scope of this book.
The first step is to remove the “fill” entry
in “ButtonBase” rectangle's style attribute.
Delete: fill:#ff0000;
.
If this is not removed, it will override any CSS style
attribute. All lines referencing “ButtonBase”
or “fill” should be deleted in the script as
the style sheet will replace their functionality.
For an internal style sheet, add a style section before the <defs> section in the SVG file as shown below. Keeping it at the top makes the style sheet easy to find. The style sheet sets the color of the base rectangle with both a default value and an override value when the button is in a pressed state. As a bonus, the style sheet also dictates that when the mouse cursor is over the button the cursor should be changed to a pointer and that the button should be highlighted.
<style type="text/css">rect[id="ButtonBase"] { fill: red; }
svg[aria-pressed="true"] rect[id="ButtonBase"] { fill: green; }
g:hover {cursor: pointer}
g:hover rect[id="ButtonGlow"] {opacity: 0; }
</style>
| |
This selector matches the rectangle with id of “ButtonBase” and assigns a “fill” value of “red” to it. | |
This selector matches the rectangle with the id of “ButtonBase” but only when the “svg” attribute aria-pressed is “true”. It overrides the previously line as it follows it in the style sheet. | |
This selector matches the | |
This selector matches the “ButtonGlow” rectangle when the cursor is above the <g> object. When the selector matches, the opacity of the “ButtonGlow” rectangle is set to zero, thereby highlighting the button (as the rectangle normally darkens the button). |
To use an external style sheet, remove the
<style>
section from the SVG file and
paste it into a separate style file, removing the opening and
closing <style>
tags. Add at the top of the
SVG file, just after the XML version and encoding line (if
present):
<?xml-stylesheet type="text/css" href="button.css" ?>
where the “href” value is the style-sheet file name. This file can be shared between the HTML and SVG, allowing one to keep all the styling in one place.
Alternatively, one can include an external style sheet by using:
<style type="text/css"> @import url(button.css); </style>
© 2005-2017 Tavmjong Bah.![]() | ![]() |