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
- Visual hiding
- Use objects as symbols (Illustrator)
<symbol>(MDN)<defs>(MDN)<use>(MDN)stroke(MDN)fill(MDN)stroke-width(MDN)currentcolorkeyword (MDN)aria-label(MDN)- Sublime text snippets
- VS Code snippets
- WebStorm LiveTemplate
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)
}
})