Another way to use SVG in React. Comfortable this time

SVG-images can be inserted directly into html code, you can use character sprites, tags <img>, <object> and even <iframe>. Can be connected SVG through data-url, css-backgrounds, css-filters and further many ways. But in order to fully use all the superpower SVGmust be inserted SVG-images directly in html– markup. Although there is actually another way. And he comfortable.

super power svg

One of the technology’s greatest strengths SVG – the ability to manipulate image styles through css. This is especially important for icons that you will definitely want to highlight on hover without the use of additional images.

To be able to recolor SVG through cssyou must either insert SVG directly to htmlthat is “inline» them, or use a separate file, a character sprite. The sprite must also be inserted into the DOM. No other technique allows access to SVG from css. Let’s take a closer look at these techniques.

Inlining

Insert SVG directly to html it is both the simplest and most powerful technique in terms of customization and image manipulation.

<span>
  <svg viewBox="0 0 16 16" width="16" height="16">
    <!-- SVG -->
  </svg>
</span>

Such an image can style via csschange almost any property and attribute, even animate its individual parts. But there are a number of significant limitations here:

  1. If the image is large, the whole page will take longer to load.

  2. Using this technique in js frameworks, even with extremely powerful tools like SVGRgreatly increases the size of the js-bundle.

  3. Lost control over loading SVG, they cease to be external images. You can’t store and cache them separately, neglect loading them on bad connections, and so on.

Character sprite

Another way to embed SVG, which allows you to style images via css, involves using a sprite consisting of elements <symbol>. Image content is stored in a separate hidden file and connected to the right place on the page through the tag <use>.

<!-- Спрайт символов наверху страницы -->
<svg style="display:none">
  <symbol id="icon" viewBox="0 0 16 16" width="16" height="16">
    <!-- SVG -->
  </symbol>
</svg>

<!-- Использование -->
<span>
  <svg><use href="#icon" /></svg>
</span>

And if you like Microsoftdo not support IE11, the character sprite can be downloaded via HTTP.

<svg>
  <use href="https://cdn.net/sprite.svg#example"/>
</svg>

Unfortunately, using this approach directly, that is, downloading the contents of a separate SVG-the image will not work, you need a sprite. Like this will not work:

<svg>
  <use href="https://cdn.net/icon.svg"/>
</svg>

Images connected via sprite can be accessed via css however, there are limitations. Styles do not “break through” through shadow-boundarythe boundary beyond which the shadow-DOM begins and which is described by the tag <use>.

The good news is that the cascade continues to work, you can change the attributes fill and use currentColor in any property. For most cases with icons, this is more than enough:

<!-- Спрайт -->
<svg style="display:none">
  <symbol id="icon">
    <path fill="currentColor">
  </symbol>
</svg>

<!-- Добавляем иконке css-класс -->
<span>
  <svg class="icon"><use href="#icon" /></svg>
</span>

<!-- Красим SVG через css -->
<style>
  .icon {
    color: rebeccapurple;
  }
</style>

Sprites are convenient, but they have a lot of their own problems, the main of which is that they are poorly extensible. Eventually the sprites grow to huge sizes and are entirely connected to the pages for the sake of using one or two icons.

Compromise

There is no compromise here. We need a solution that will load only the necessary SVG-images, will not render them via javascript and will allow them to be styled via css.

Such a solution can be a browser fetch! We need a tool that

  1. Will load SVG-images in browser via fetch and cache them

  2. Add them to the character sprite

  3. Provides an API for using uploaded images in an arbitrary section of the page through a tag <use>.

I was the first to think about this decision. Chris Coyier back in 2015, but it was never formalized and was waiting for its day. Today that day has come.

handy svg

The implementation is called handy svgsources and documentation are available at githubthe package is published to npm. You just need to install it:

npm i handy-svg

And use in React:

import {HandySvg} from 'handy-svg';
import iconSrc from './icon.svg';

export const Icon = () => (
    <HandySvg
        src={iconSrc}
        className="icon"
        width="32"
        height="32"
    />
);

Or in any other vanilla javascript project:

import {injector} from 'handy-svg/lib/injector';

const src = "https://cdn-server.net/icon.svg";

// Загружает изображения и добавляет их в спрайт
injector.load(src);

// Доступ к id изображения
const id = injector.getId(src);

// Использование
const svg = `<svg class="icon"><use href="#${id}" /></svg>`;

There will be no styling issues.

.icon {
  color: rebeccapurple;
}

Only the necessary images will be loaded on the page, you can cache them, and in SPA applications, of course, requests will not be sent twice. Your sprite will not grow and you will not even think about its existence.

Of course, this solution has some limitations. For example, it’s nearly impossible to get rid of FONI (Flash of No Icons), a loading state where there are no icons on the page. However, of all the possible ways to work with SVG-images on the web, this one seems to be the most convenient.


Pull requests are welcome and I welcome any feedback.

Similar Posts

Leave a Reply