Як легко підключити SVG спрайти в Nuxt або Vue проект

Чому спрайти взагалі вигідні? Тому що без спрайтів у вас завантажується кожна іконка окремо, на кожній новій сторінці, що части викликає проблему видимості завантаження, особливо при паганому інтернеті. Спрайт завантажується 1 раз, після відразу кешується, і всі іконки на всіх сторінках, будуть вже завантажені, що і спонукає багатьох розробників до їх використання.

Плюс, треба враховувати, якщо вам потрібно керувати кольором іконок, то SVG спрайти єдине правельне рішення.

Почнемо з азів, вам знадобиться модуль svg-sprite-generator

Після його встановлення додайте до вашего watcher, або просто в package.json команду, яка буде збирати спрайт:

"scripts": {
    "icons": "svg-sprite-generate -d ./assets/icons -o ./public/sprite.svg",
},

З наведенного прикладу, svg іконки знаходяться в папці assets/icons, а кластися спрайт буде в папку паблік.

Далі нам потрібно створити компонент, котрий буде чистати іконки з файлу, на прикаладі icon.vue:

<template lang="pug">
svg.v-icon(xmlns="http://www.w3.org/2000/svg" :width='size.w', :height='size.h', :class="'icon-'+ name")
  use(:href="'/sprite.svg'+'#'+name" )
</template>

<script>
export default {
  computed: {
    size() {
      const w = this.s && this.s.toString().includes(',') ? this.s.split(',')[0] : this.s || 32;
      const h = this.s && this.s.toString().includes(',') ? this.s.split(',')[1] : this.s || 32;
      return {
        w: `${w}px`,
        h: `${h}px`,
      }
    }
  },
  props: {
    s: {
      type: [String, Number],
      default: 32
    },
    name: {
      type: String,
      require: true
    }
  }
}
</script>

Він достатньо простий, але це нам і потрібно.

Тепер до використання, в компонентах:

<template lang="pug">
div
  icon(name="arrow-left" s="20,10")
</template

Модуль генерить іконки по назві файлу, тобто якщо файл називався arrow-left.svg, то так його потрібно і викликати. Модуль генерить спрайти в виді svg <symbol>, тому тут є певні нюанси. Одним із такиї є неможливість використання додаткових стилів всередині файла, типу svg <defs>, якщо такий буде в якомусь файлі іконки, то генератор взагалі не зможе сгенерувати спрайт. Вам доведеться вручну заходити в кожен файл іконок, та вичищати <defs>. Але це не є проблемою модулю, це є особливість svg symbol спрайтів. 

Тепер у вас може постати питання, як керувати кольором, чи додати до іконки із спрайта градієнт, так як <defs> використовувати неможливо. Дуже просто. Вам потрібно вичистити з іконки, всі html tags, які відповідають за колір, тобто fill та stroke. Після очистки, файл іконки повинен вигядати приблизно так:

<svg width="26" height="26" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg">
<path d="M13 26C20.1797 26 26 20.1797 26 13C26 5.8203 20.1797 0 13 0C5.8203 0 0 5.8203 0 13C0 20.1797 5.8203 26 13 26Z" fill-opacity="0.08" />
<path d="M7.68024 9.7501L6.66276 10.7676L12.9825 17.0873L14 16.0699L7.68024 9.7501Z" />
<path d="M11.9448 16.0708L12.9628 17.0889L19.2826 10.7691L18.2645 9.75104L11.9448 16.0708Z" />
</svg>

Ви можете використовувати не тільки path, а і rect, circle та будь що інше, це просто як для прикладу. Як ви бачите в іконці нема ніяких fill чи stroke, кольрами ви можете управляти через css напряму з вашого компонента. Наприклад:

<template lang="pug">
.component
  icon.component__icon(name="arrow-left" s="20,10")
</template

<style lang="stylus">
.component
  &__icon
    fill green
    stroke #FFA000
    &:hover
       stroke #000
</style>

З кольорами зрозуміло, але є ще градієнти, з цим трохи складніше. Вам потрібно підключити SVG gradient через <defs> напряму в ваш індексний файл, або файл леяута, я підключаю в app.vue:

<template lang="pug">
.g
  RouterView(v-slot="{ Component }")
      transition(:name="transitionName" )
        component(:is="Component")

  svg(style="width:0;height:0;position:absolute;" aria-hidden="true" focusable="false")
    linearGradient#gradient(gradientTransform="rotate(65)")
      stop(offset="0%" stop-color="#00c5ff")
      stop(offset="100%" stop-color="#0095ff")
</template>

Таких ви можете підключити скільки завгодно, головне щоб в них був різний ID, в прикладі ID #gradient. Теперь через тіж самі стилі ви зможете додати і градієнт:

<template lang="pug">
.component
  icon.component__icon(name="arrow-left" s="20,10")
</template

<style lang="stylus">
.component
  &__icon
    fill url(#gradient)
</style>

Це все. Щодо важливих нюансів. Деякі іконки можуть бути намальвані так, що якщо ви не задасте fill none, або stroke none, у вас будуть просто чорні квадрати, це вже залежить від дизайнера, якщо ви з таким зіткнулись, спробуйте задати іконці stoke: none, або fill: none.

На цьому точно все, дякую за увагу.