Key Takeaways
- Icon fonts block rendering and create accessibility issues that SVG sprites do not.
- An SVG sprite is a single file containing every icon as a named
<symbol>, referenced with<use>anywhere in your HTML. - You can automate sprite generation with
svg-spriteorsvgovia a Gulp or Vite build step. - Bootstrap Icons 1.11 ships individual SVG files ready to compile into a sprite, making the swap straightforward.
- Canvas HTML Template users can replace the bundled icon font references without touching core layout files.
- Colour, size, and animation are all controlled through CSS, just as they were with icon fonts.
Why Replace Icon Fonts at All
The performance case is concrete. A typical icon font such as Font Awesome 6 Free loads a WOFF2 file of roughly 150 to 200 KB. The browser must download that file, parse it, and apply it before any ::before pseudo-element renders. On a slow 3G connection that is a visible flash of missing icons. On a fast fibre connection it is a silent layout shift that still affects Cumulative Layout Shift scores.
The accessibility case is equally clear. Screen readers vary in how they handle Unicode private-use area characters. VoiceOver on iOS will sometimes read out a raw codepoint or the word “private use character”. Wrapping every icon in aria-hidden="true" is the standard workaround, but it is easy to miss one. SVG elements accept <title> and aria-label natively, making accessible icons the default rather than the exception.
If you are building performance-optimised pages, this fits naturally alongside other asset decisions. The same thinking that drives you to serve WebP and AVIF images from a static HTML template applies here: every byte counts, and formats matter.

Understanding SVG Sprites
An SVG sprite is a plain .svg file that acts as a container. Each icon lives inside a <symbol> element with a unique id. The symbols are hidden by default. To display any icon, you write a tiny <svg><use> fragment that references the symbol by id.
<!-- Inside sprite.svg -->
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="icon-arrow-right" viewBox="0 0 16 16">
<path d="M1 8h14M9 2l6 6-6 6"/>
</symbol>
<symbol id="icon-check" viewBox="0 0 16 16">
<path d="M2 8l4 4 8-8"/>
</symbol>
</svg><!-- Usage anywhere in the page -->
<svg class="icon" aria-hidden="true" focusable="false">
<use href="/assets/img/sprite.svg#icon-arrow-right"></use>
</svg>The href value can point to an third-party file, which the browser caches across pages, or to an inline sprite placed at the top of the body, which avoids any extra request and is ideal for above-the-fold icons. Both approaches work in all browsers that support Bootstrap 5.
Generating a Sprite from Bootstrap Icons SVG Files
Bootstrap Icons 1.11 ships as individual SVG files inside a bootstrap-icons/icons/ directory. Each file is a standalone SVG optimised for a 16×16 viewBox. That makes them ideal sprite candidates.
Install the package and the svg-sprite build tool:
# run in your project root
npm install bootstrap-icons svg-sprite --save-devCreate a minimal sprite.config.json:
{
"mode": {
"symbol": {
"dest": "dist/img",
"sprite": "sprite.svg",
"prefix": "icon-%s"
}
},
"shape": {
"id": {
"separator": "-"
}
}
}Add a build script to package.json:
"scripts": {
"sprite": "svg-sprite --config sprite.config.json node_modules/bootstrap-icons/icons/*.svg"
}Running npm run sprite produces dist/img/sprite.svg containing every Bootstrap Icon as a named symbol. File size is where discipline pays off: passing a glob that lists only the icons your template actually uses, rather than all 1,900-plus, reduces the sprite to under 30 KB. Selecting around 40 icons is a reasonable target for most marketing templates.
For teams already using Gulp or Vite in their HTML template workflow, integrating this step is covered in the post on Gulp vs Vite vs Webpack for HTML template workflows.

Migrating from Icon Font Markup
Icon fonts typically use a class-based pattern. Bootstrap Icons in font mode look like this:
<!-- Icon font (before) -->
<i class="bi bi-arrow-right"></i>The SVG sprite equivalent is:
<!-- SVG sprite (after) -->
<svg class="icon" aria-hidden="true" focusable="false" width="16" height="16">
<use href="/dist/img/sprite.svg#icon-arrow-right"></use>
</svg>For a large template with hundreds of icon references, a find-and-replace regex across your HTML files handles most of the work. A pattern like <i class="bi bi-([a-z-]+)"></i> can be replaced with the SVG fragment using a simple Node.js script or a sed command in your build pipeline.
Inside the Canvas HTML Template, icon references are concentrated in navigation elements, feature sections, and footer icon rows. Those areas map neatly to sprite symbols. The Canvas footer components, for instance, use social and UI icons that repeat across multiple pages. A sprite defines those symbols once and references them everywhere, rather than each page loading a separate font file.
Controlling Colour and Size with CSS
A common objection to SVG sprites is that styling feels harder than with icon fonts, which simply inherit color and font-size. In practice the gap is small. Use currentColor inside the SVG paths and the icon inherits the parent element’s colour automatically.
Set a base icon size using width and height attributes or CSS:
/ In your stylesheet /
.icon {
width: 1em;
height: 1em;
fill: currentColor;
vertical-align: -0.125em; / aligns with text baseline /
}Because Canvas uses Bootstrap 5 CSS custom properties, you can key icon colours directly to the theme. For example:
.icon-primary {
color: var(--cnvs-themecolor);
}Hover states, transitions, and CSS animations work exactly as they would on any other element. A rotating loader icon is a single @keyframes rule applied to the .icon class.
Making SVG Sprite Icons Accessible
The rule is simple. Decorative icons get aria-hidden="true" and focusable="false". Meaningful standalone icons, such as a button with only an icon and no visible label, need an accessible name:
<!-- Decorative: hidden from assistive tech -->
<svg class="icon" aria-hidden="true" focusable="false">
<use href="/dist/img/sprite.svg#icon-check"></use>
</svg>
<!-- Standalone icon button: labelled -->
<button type="button" aria-label="Close menu">
<svg class="icon" aria-hidden="true" focusable="false">
<use href="/dist/img/sprite.svg#icon-x"></use>
</svg>
</button>The focusable="false" attribute is specifically required for Internet Explorer 11 compatibility. That is not a concern for most projects in 2025, but keeping it as a habit costs nothing, and some enterprise intranet requirements still reference IE11 support. The label belongs on the interactive element, not the SVG, which is the cleanest pattern for screen readers.
This pairs directly with accessible component work. If you are also working through keyboard navigation and ARIA patterns on interactive components, the guidance in making Bootstrap 5 modals accessible applies the same philosophy to focus management.
Performance Results and When Not to Switch
Replacing a 180 KB icon font with a 28 KB subset sprite removes one render-blocking resource and reduces total page weight noticeably. In Lighthouse testing on a typical marketing page, switching from Font Awesome 6 Free to a curated SVG sprite has been observed to improve Largest Contentful Paint by 200 to 400 milliseconds on a simulated slow 4G connection, depending on how far up the page the icon font reference appeared.
That said, SVG sprites are not always the right call. Three situations where a different approach makes more sense:
- Very small icon sets (5 or fewer icons): Inline SVG directly in the HTML is simpler and avoids the sprite infrastructure entirely.
- CMS-generated content where markup is tightly controlled: If your CMS outputs
<i class="bi bi-star">and you cannot change the template, the sprite swap requires a CMS-level change, not just a front-end one. - Teams unfamiliar with the build process: The sprite generation step adds tooling complexity. On a straightforward one-page site, the trade-off may not justify the setup time.
Frequently Asked Questions
An inline sprite is placed directly in the HTML document, typically just after the opening <body> tag. It requires zero additional HTTP requests and renders immediately, making it ideal for icons visible above the fold. An third-party sprite lives in a separate .svg file referenced via href. It is cached by the browser across multiple pages, which is more efficient for large multi-page sites. Both approaches work with the <use> element. The third-party file approach requires a server or a build step that copies the sprite into your dist folder.
Yes. Bootstrap Icons 1.11 ships individual .svg files and you can use them as <img> elements or inline SVGs. Individual <img> references create one HTTP request per icon, which defeats the performance goal. Inline SVGs avoid requests but bloat your HTML. A sprite gives you the best of both: one cached request for all icons, with clean reusable references.
Two-tone icons use multiple <path> elements within the symbol, each with a different fill or opacity value. You can target individual paths via CSS using the nth-child selector or by adding class names to the paths inside the symbol. The limitation is that CSS cannot target paths inside an third-party sprite referenced via <use> due to the shadow DOM boundary. For multi-colour icons that need full CSS control, inline the SVG directly in the HTML rather than using a sprite reference.
Not directly. Search engines do not index icon content. The indirect benefit comes from the performance improvement: faster page loads contribute positively to Core Web Vitals, particularly LCP and CLS, which are confirmed Google ranking signals. Removing a render-blocking font resource is a genuine improvement to page speed, which is why this migration is worth measuring with Lighthouse before and after deployment.
The safest approach is to add a new .icon CSS class rather than modifying Canvas’s existing stylesheet. Place your icon CSS in a custom partial that loads after plugins.min.js and the main Canvas stylesheet. Replace icon font <i> elements one section at a time, testing visually as you go. Canvas’s use of CSS custom properties, including --cnvs-themecolor, means your icon colours can reference the same variables as the rest of the design with no duplication.
Looking for a production-ready Bootstrap 5 HTML template? Browse Canvas Template demos and find the perfect starting point for your next project.
If you’re building with the Canvas HTML Template and want to ship production-ready Bootstrap 5 layouts faster, try Canvas Builder free — the visual builder that exports clean Canvas-ready markup in minutes.
Skip the setup and build it free
Spin up a complete Bootstrap 5 site, blog included, with Canvas Builder. No coding, no cost.
Canvas Team
Tutorials and tips for building beautiful Bootstrap 5 websites with the Canvas HTML Template and Canvas Builder.
More from the Canvas Blog