An SVG Button—SVG and the Web

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.

An SVG button.
An SVG button.

The steps are:

[Warning]SVG in HTML5

SVG in HTML5 is a work in progress. The HTML5 standardization process in not complete. The are major inconsistencies in how different browsers handle SVG content in HTML. Work is being done to make the integration of SVG into HTML easier for the web designer.

Procedure 1.8. Creating an SVG Button

  1. 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.

    1. Set up the drawing.

      With the Document Properties dialog (File icon Document Properties... (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 ( icon in Snap Bar).

    2. Draw the base rectangle.

      Draw a rectangle 220 × 80 pixels centered on the page (upper-left corner at 20, 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.

      Button base.
      The base of the button.

      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 (Object icon Object Properties... (Shift+Ctrl+O)) or the XML Editor dialog (Edit icon XML Editor... (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.

      XML Editor dialog.
      XML Editor dialog (after rectangle relabeled).
    3. 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 icon in the Tool Controls.

      The next step is to convert the rectangle to a path via Path icon Object to Path (Shift+Ctrl+C). Then, with the Node Tool, select the two (possibly four) side nodes and convert then to Auto-smooth Nodes by clicking on the Make selected nodes auto-smooth ( icon ) icon in the Tool Controls. Next move the bottom two nodes up 15 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 ) 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 top color is not white, click on the top Gradient handle (a square) and click on the white square in the Palette. You may also need to set the bottom handle (a circle) to white but with an Alpha of zero. To do this you must either use the Gradient Editor dialog or the Fill and Stroke dialog.

      Finally, with the XML Editor dialog, change the id of the path to ButtonHighlight.

      Button with highlight.
      After adding the highlight.
    4. 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 (Edit icon Duplicate (Ctrl+D)). Change the Fill to black. Now use the Gradient Tool to create a Radial Gradient by clicking on the icon 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 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.

      Button with glow.
      After adding the glow.

      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.

    5. 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. In v0.48, the snapping point for center-aligned text is in the center. In v0.47 one can use the Align and Distribute dialog to center the 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.

      Button with text.
      After adding some text.

      Finally, save the button as button.svg.

  2. 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>     1
    <html xmlns="http://www.w3.org/1999/xhtml">     2
      <head>
    
        <meta charset="UTF-8"/>     3
    
        <title>Sample use of an SVG Button</title>
    
      </head>
      <body>
    
        <h1>An SVG button</h1>
    
        <a href="http://tavmjong.free.fr/INKSCAPE/">
          <img src="button.svg" alt="A sample button."/>     4
        </a>
    
      </body>
    </html>
         
         

    1

    HTML declaration. (With HTML5 no dtd is required.)

    2

    HTML Name Space declaration. The XML syntax is specified here.

    3

    The character encoding of the file (normally UTF-8).

    4

    Inclusion of the SVG file via the <img> tag.

    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.

  3. 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 will not be supported in Internet Explorer 9 (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.

    Throbbing button.
    The throbbing button.
  4. 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">     1
        function buttonEvent(event) {     2
          if ((event.type == "click" &amp;&amp; event.button == 0) ||
              (event.type == "keydown" &amp;&amp;
    	  (event.keyCode == 32 || event.keyCode ==13))) {     3
    
            var SVGDocument = event.target.ownerDocument;     4
            var SVGRoot     = SVGDocument.documentElement;
            var ButtonBase  = SVGDocument.getElementById("ButtonBase");
            var Text        = SVGDocument.getElementById("Text");
            var TextShadow  = SVGDocument.getElementById("TextShadow");
    
            var pressed = false;     5
            var fill = "red";
            var text = "OFF";
    
            if ("false" == SVGRoot.getAttribute("aria-pressed")) {     6
              pressed = true;
    	  fill = "green";
    	  text = "ON";
            }
    
            SVGRoot.setAttribute("aria-pressed", pressed);     7
            ButtonBase.style.setProperty("fill", fill, "");
            Text.firstChild.nodeValue = text;     8
            TextShadow.firstChild.nodeValue = text;
          }
        }
      </script>
         

    1

    Start of script section. The type must be declared as text/ecmascript.

    2

    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.

    3

    The event is checked to make sure it is of a type we are interested in.

    4

    References are obtained to the relevant SVG objects.

    5

    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.)

    6

    Variables are toggled if necessary.

    5

    The necessary attributes and properties are set.

    8

    The text is changed. Note that the text is stored in a child node of the <tspan> object.

    Two state button.
    A two state button. Try it! The button is OFF.

    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>
         

    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 );).

  5. 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">     1
        rect[id="ButtonBase"] { fill: red; }     2
        svg[aria-pressed="true"] rect[id="ButtonBase"] { fill: green; }     3
        g:hover {cursor: pointer}     4
        g:hover rect[id="ButtonGlow"] {opacity: 0; }     5
      </style>
         

    1

    <style> start tag with type declaration.

    2

    This selector matches the rectangle with id of ButtonBase and assigns a fill value of red to it.

    3

    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.

    4

    This selector matches the <g> object, but only when the cursor is above the Group. When the selector matches, the cursor is changed to a pointer.

    5

    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).

    Styled Button.
    The button styled via CSS.

    That completes styling the SVG with an internal CSS style sheet. 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.