en
SVG спрайты. Как правильно готовить?

SVG спрайты. Как правильно готовить?

Во время рефакторинга одного древнего проекта оказалось, что в нём иконки на страницы добавлялись 5-ю различными способами, от инлайновой вставки SVG до иконочных шрифтов. Для этого были написаны 3 Gulp задачи. Так как стояла задача рефакторинга, я решил унифицировать способ вставки иконок. Сначала хотел использовать библиотеку символов, но этот популярный метод создания SVG спрайтов имеет один серьёзный недостаток — он не умеет работать с фоновыми изображениями. Сейчас мы исправим этот недостаток.

В этой статье я не буду рассматривать классический способ создания спрайтов, так как он хорошо всем известен. SVG символы затрону лишь кратко и остановлюсь на той части, которая позволяет реализовать вставку фоновых иконок.

В чём проблема классических спрайтов?

Классический спрайт представляет собой один файл (SVG или растровый) с размещёнными на нём иконками. Выборку используемой иконки предлагается делать используя позиционирование фонового изображения.

В чём недостатки такого способа?

  • Нужны дополнительные инструменты, чтобы создать комплексное изображение (онлайн или в виде npm пакета).
  • Нельзя менять цвет иконок в CSS.
  • Нельзя получить доступ к иконкам из JavaScript.

Часть этих недостатков компенсируется использованием библиотеки SVG символов.

Вкратце напомню. В файл SVG добавляются иконки в теге <symbol>.

<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="cart" viewBox="0 0 32 32">
    <path fill="currentcolor" d="M21.65…" />
  </symbol>
  <symbol id="user" viewBox="0 0 32 32">
    <path fill="currentcolor" d="M18.34…" />
  </symbol>
</svg>

В темплейте иконка выводится в виде инлайнового SVG со ссылкой на ID символа.

<svg viewBox="0 0 32 32" width="32" height="32" aria-hidden="true">
  <use href="sprite.svg#cart" />
</svg>

Достоинства таких спрайтов:

  • Можно менять стили из CSS.
  • Можно использовать JavaScript.
  • Можно использовать CSS Custom Properties (CSS переменные).
  • Назначив currentColor вместо цвета, можно управлять цветом из CSS по свойству color.
  • Возможность полностью контролировать SVG, вырезая из него ненужное для облегчения веса.
  • Возможность использовать несколько спрайтов для разных секций сайта, не переписывая задачи для Gulp/Webpack.

Единственный недостаток SVG символов, как уже указывалось — отсутствие поддержки фоновых картинок. И тут к нам на помощь приходит технология SVG Stacks.

SVG Stacks — решение проблемы

В темплейте спрайт выводится тем же образом как и в SVG символах.

<svg viewBox="0 0 32 32" width="32" height="32" aria-hidden="true">
  <use href="sprite.svg#cart" />
</svg>

В файле спрайта начинаются перемены. Первым делом заменяем <symbol> на <svg>. Да, именно так, SVG внутри SVG, как в фильме Нолана «Начало». Таким образом у нас есть внешний SVG и внутренние обёртки.

<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <style>
      :root svg:not(:target) {
        display: none;
      }
    </style>
  </defs>

  <svg id="cart" viewBox="0 0 32 32">
    <path fill="currentcolor" d="M21.65…" />
  </svg>

  <svg id="user" viewBox="0 0 32 32">
    <path fill="currentcolor" d="M18.34…" />
  </svg>
</svg>

Мы добавляем display: none, т. к. все внутренние SVG будут отображаться по умолчанию. Используя псевдоэлемент :target мы отображаем только текущую иконку, к которой обращаемся по ID. Всё остальное ничем не отличается от использования SVG символов.

Фоновые изображения

А теперь самое интересное. Как вывести иконки фоновым изображением?

a {
  background-image: url('sprite.svg#cart');
}

Единственное ограничение такого подхода, в том, что мы не можем явно поменять цвет заливки иконки таким образом:

a {
  background-image: url('sprite.svg#cart');
}

a:hover {
  fill: 'darkgray';
}

Для этого нам нужно создать «экземпляры» иконки внутри спрайта:

<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <style>
      :root svg:not(:target) {
        display: none;
      }
    </style>

    <!-- Иконка -->
    <path id="cart" d="M21.65…" />
  </defs>

  <!-- «Экземпляр» иконки -->
  <svg id="cart-default" viewBox="0 0 32 32">
    <use href="#cart" fill="gray" />
  </svg>

  <!-- «Экземпляр» иконки на ховере -->
  <svg id="cart-hover" viewBox="0 0 32 32">
    <use href="#cart" fill="darkgray" />
  </svg>
</svg>

И теперь можно вывести фоновые иконки:

a {
  background-image: url('sprite.svg#cart-default');
}

a:hover {
  background-image: url('sprite.svg#cart-hover');
}

Прозрачные области в Firefox

Если в иконке есть прозрачные области, в браузере Firefox курсор может пропускать их на ховере. Поэтому добавляем прозрачный квадрат вокруг иконки.

<svg id="cart" viewBox="0 0 32 32">
  <rect width="32" height="32" fill-opacity="0" />
  <path fill="currentcolor" d="M21.65…" />
</svg>

Я думаю эти два недостатка с лихвой компенсируют содержание в проекте зоопарка из нескольких методов создания спрайтов.


Ссылки:

Последнее обновление: