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 SVG
must 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 css
you must either insert SVG
directly to html
that 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:
If the image is large, the whole page will take longer to load.
Using this technique in js frameworks, even with extremely powerful tools like SVGRgreatly increases the size of the js-bundle.
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
Will load
SVG
-images in browser viafetch
and cache themAdd them to the character sprite
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.