Hajime, the duck guy

UX and graphics kata
On this page
Level: Essential

SVG spritesheet

Create a SVG spritesheet from the provided icons

The way of kata

Kata is an exercise for muscle memory. It's not intended to fill your brain with information but train your fingers to react. The information is there to give you the why, but your fingers need to learn the how.

The material on this page is presented in a specific order — from least specific to highly technical. You will learn the most by jumping in as soon as you have some idea of what you should do. Once you're done, read the rest of the material and check your solution.

All katas are designed to be doable without using 3rd party libraries (and, in fact, the point is to also learn how to do what these libraries do).

To make the best of katas, observe the following rules.

  • Don't rush.
  • When stuck, take a break and do something unrelated.
  • Do not copy/paste code. Always retype everything.
  • Do not use AI tools to generate code.
  • Try to do something that wasn't in the instructions, experiment.
  • Repeat the kata from time to time, even if you think you've got it.
  • You have mastered the kata once you are able to complete it without thinking too much.

Remember, the goal is not to get it done, but to get some practice.

Introduction

In this exercise you will practice creating and using SVG spritesheets.

Skills you will acquire

  • Creating SVG spritesheets
  • Adding icons to the page
  • Providing text fallback for icons
  • Hiding elements from screen readers

Objective

  • Creating SVG spritesheets
  • Adding icons to the page
  • Controlling the appearance of the icons using CSS
  • Providing text fallback for icons

Check your solution

  • Create a SVG spritesheet from the provided SVG files
  • Make sure the icons use surrounding text color when inserted into the page
  • Create elements on the page that showcase all of the icons
  • Create a button with a 'plus' icon with "Add" as a label
  • Create a button with a 'minus' icon and no visible text
  • When the page is read by a screenreader, icons are spoken as their content
  • When the plus button is read by a screen reader, it is read as "Add"
  • When the minus button is read by a screen reader, it is read as "Remove"

Materials

Tools

Keep in mind

SVG spritesheet is a SVG file that contains a collection of different SVG graphics that can be referenced using their id attribute. Of the several common methods for adding icons to a page, SVG spritesheet combines the advantages of using an external resource (e.g., caching), with the flexibility of the inline SVG format without bloating the HTML too much.

Unlike icon fonts, the SVG spritesheet images can use multiple colors in the same graphic, and aren't subjected to font overrides when users decide to apply their custom stylesheets. They are also advantageous in that more visual aspects can be controlled from CSS.

SVG spritesheets have some drawbacks compared to the icon fonts, however. For example, icon fonts compress better, and can be used in situations where SVG cannot (e.g., ::after and ::before pseudo-elements), and CSS cannot control which icon is shown (you have to modify the HTML). SVG spritesheet is a lot more verbose in the markup as, unlike icons, they require markup, and aren't apply solely using selectors in CSS.

You can either create the SVG spritesheet manually, use the symbol feature in Adobe Illustrator, or use the SVG Spirit app. The last approach is the easiest when you already have exports SVG images as in this case. Try all approaches that you can, however. The first two approaches — and especially using Adobe Illustrator — have the advantage of giving you the ability to reuse graphics across other graphics, and results in a more compact output when you have repeating shapes.

The spritesheets are added to the page in the form of embedded SVG markup that contains only a single <use/> tag. Note the presence of the / in the null (self-closing) tag. This is because SVG markup is XML and not HTML. Unlike HTML, the / is valid, and required.

<svg><use href="spritesheet.svg#plus"/></svg>

The default size of the icon matches the default size of the <svg> element, as determined by the browser. Because of this, we typically add additional styling to the icon so that it matches the surrounding text. This may include setting the width and height (or aspect ratio) of the <svg> element (try values between 1em and 1.5em and see what works best).

Note that embedded SVG, and by extension the symbol from the referenced SVG will honor CSS variable if defined by the document. This cna be used to dynamically change the stroke color, fill color, stroke width and similar characteristics of the icons. Try playing with these elements which what you can do with them. The SVG Spirit app has editors for colors and stroke width which lets you remap them to any value of your choosing including arbitrary CSS variables (use can use the variable editor to test the variables).

In addition to including icons, SVG spritesheets can be used for just about any type of SVG graphic, including such things as site/app logos, illustrations, etc. Since they are bundled in the same SVG file, they get shipped as a single file rather than separate files, which can mean more efficient downloading depending on how many of these graphics you use on the same page at the same time. As usual, you need to test to see if you are gaining or losing something. Try including some graphics into the spritesheet and see how they render.

Generally speaking, we use icons in two ways. We use them either to augment some text content, or we use them to replace the text content. In either case, you should make sure that the screen reader is able to announce the intended information. For instance, if a button only shows a single icon, you should ensure that the meaning visually able people get from the icon is also conveyed to those who cannot (clearly) see the icon. Text alternatives are provided in order to achieve this. You can think of text alternatives as the alt attribute on the <img> tag.

Since not all elements have a built-in equivalent of an alt attribute, we have several approaches to provide text alternative. For practice, you should try different approaches as some work better than others in different scenarios.

The two most common approaches are using aria-label, and visual hiding.

The easiest way to provide a text alternative for an element is to use the aria-label attribute. For example:

<button aria-label="plus">
  <svg class="icon"><use href="spritesheet.svg#plus"/></svg>
</button>

The downside of using aria-label is that it does not work on all elements. There are other rules about using aria-label which may not be immediately obvious. Be sure to read up on the attribute and learn how to use it properly. As is generally the case with anything ARIA-related, when in doubt, avoid using.

The second approach is to include the text label in the element. This has the advantage of being supported by virtually all accessibility tools. On the other hand it requires us to remove the text using CSS in a way that doesn't circumvent those tools. We commonly use a technique called 'visual hiding' for this.

.text-alt {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
}

The reason properties like visibility are not used for this is that accessibility tools generally try to honor CSS as much as possible to account for pages that aren't designed with accessibility in mind.

In case of icons, we would make the text visually hidden by wrapping it in a <span> and hiding the <span>:

<span>
  <svg class="icon"><use href="spritesheet.svg#plus"/></svg>
  <span class="text-alt">plus</span>
</span>

With the example markup would apply the visual hiding CSS to the inner span only.

Unlike icon fonts which use non-readable characters the <svg> element is a graphical element. This is why screen readers may read it as "graphic". To suppress this, we typically mark the element as hidden:

<li>
    <svg class="icon" aria-hidden="true">
        <use href="spritesheet.svg#folder"/>
    </svg>
  Documents
</li>

Use a screen reader to test this with and without the aria-hidden attribute.

As mentioned previously, the markup for the SVG spritesheet icons can be quite verbose. The simplest solution for this is to use snippets or live templates in your editor to generate the markup. Try setting your editor up to generate the markup. Alternatively, you can use some JavaScript and custom elements for the purpose, to reduce the amount of markup to begin with. For example, try implementing something like this:

<x-icon name="plus"></x-icon>

Reading list

Hints & spoilers

Spoiler: custom element to render icons
var ICON_TEMPLATE = '<svg class="icon" aria-hidden="true"><use/></svg>'

customElements.define('x-icon', class extends HTMLElement {
    static observedAttributes = ['name']

    attributeChangedCallback() {
        // This callback is also invoked initially when the 
        // custom element is connected, not just when the 
        // attribute is changed form its initial value
         
        var name = this.getAttribute('name')
        if (!this.firstChild) // don't render every time 
            this.innerHTML = ICON_TEMPLATE
        var use = this.querySelector('use')
        use.setAttribute('href', 'spritesheet.svg#' + name)
    }
})

Want more?

Back to top