Menggunakan SVG Sprite Untuk Ikon di Blog

I love SVG. Love at the first sight.
Kala itu hati ini terpesona mendapati gambar yang bisa diperbesar tampilan tanpa kehilangan mutunya.
Dalam blog ini pun setidaknya telah dua artikel yang membahas SVG, dan kini saya akan menambahkannya satu lagi.

Pengelola blog tentunya telah mafhum mengenai pentingnya penggunaan ikon di dalam blog. Pada umumnya blog modern, ikon ini biasanya didapat dari Font Awesome. Baik yang menempatkan fontanya di blog atau dengan menggunakan layanan CDN dari Font Awesome.
Awalnya saya juga demikian, namun setelah beralih ke GitLab Pages berniat untuk meminimalkan penggunaan resource dari luar.

Upaya pertama untuk tidak menggunakan layanan ikon dari luar adalah dengan melekatkan (embed) ikon SVG ke dalam laman blog. Namun cara ini memiliki dua kelemahan utama;

  1. Membuat ukuran berkas laman blog menjadi besar. Akan sangat terasa jika blognya memiliki banyak artikel.
  2. Ikon tidak bisa cached (disimpan di lokal oleh browser).

Dua hal di atas pastinya akan membebani bandwidth pengunjung blog.

Upaya kedua adalah dengan membuat berkas gambar SVG untuk tiap ikon. Ini akan mengatasi kelemahan nomor 1 di atas, namun dengan memunculkan kelemahan yang lain yakni request tambahan untuk mengambil berkas-berkas gambar SVG tersebut.
Walau request ini hanya diperlukan bagi pengunjung yang belum pernah mengunjungi blog ini (dan karenanya ikon belum cached), namun saya cenderung kurang menyukainya karena berarti menambah banyak jumlah berkas di blog (file management is PITA, and I’m kind of OCD).

Sampai akhirnya mendapat ilham berkat seseorang di grup PegeLinux yang menyinggung SVG sprite. Yeah, mengapa tidak menjadikan berkas-berkas ikon SVG ini menjadi satu berkas SVG sprite saja? Menggunakan SVG sprite menjawab 3 kelemahan yang telah dibahas di awal:

  1. Membuat ukuran berkas laman blog menjadi kecil karena tidak ada ikon yang embedded
  2. Ikon akan bisa disimpan di tembolok (cached) peramban web
  3. Hanya perlu satu berkas SVG untuk banyak ikon, yang artinya hanya perlu request dan menyimpan satu berkas

Demikian kisah bagaimana akhirnya blog ini menggunakan SVG sprite untuk ikon-ikon navigasinya. Dan berikut di bawah adalah catatan langkah demi langkahnya.

Membuat berkas SVG sprite

SVG sprite pada dasarnya adalah sebuah berkas SVG yang memiliki banyak simbol di dalamnya. Di bawah ini adalah berkas telegram.svg dari Font Awesome.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512">
  <path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm121.8 169.9l-40.7 191.8c-3 13.6-11.1 16.9-22.4 10.5l-62-45.7-29.9 28.8c-3.3 3.3-6.1 6.1-12.5 6.1l4.4-63.1 114.9-103.8c5-4.4-1.1-6.9-7.7-2.5l-142 89.4-61.2-19.1c-13.3-4.2-13.6-13.3 2.8-19.7l239.1-92.2c11.1-4 20.8 2.7 17.2 19.5z"/>
</svg>

Dan di bawah ini adalah berkas svg-sprites.svg yang saya gunakan di blog ini.

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="archive">
    <path d="M488 128H24c-13.255 0-24-10.745-24-24V56c0-13.255 10.745-24 24-24h464c13.255 0 24 10.745 24 24v48c0 13.255-10.745 24-24 24zm-8 328V184c0-13.255-10.745-24-24-24H56c-13.255 0-24 10.745-24 24v272c0 13.255 10.745 24 24 24h400c13.255 0 24-10.745 24-24zM308 256H204c-6.627 0-12-5.373-12-12v-8c0-6.627 5.373-12 12-12h104c6.627 0 12 5.373 12 12v8c0 6.627-5.373 12-12 12z"></path>
  </symbol>
  <symbol id="arrow-alt-circle-up">
    <path d="M256 504c137 0 248-111 248-248S393 8 256 8 8 119 8 256s111 248 248 248zm0-448c110.5 0 200 89.5 200 200s-89.5 200-200 200S56 366.5 56 256 145.5 56 256 56zm20 328h-40c-6.6 0-12-5.4-12-12V256h-67c-10.7 0-16-12.9-8.5-20.5l99-99c4.7-4.7 12.3-4.7 17 0l99 99c7.6 7.6 2.2 20.5-8.5 20.5h-67v116c0 6.6-5.4 12-12 12z"></path>
  </symbol>
  <symbol id="arrow-alt-circle-left">
    <path d="M8 256c0 137 111 248 248 248s248-111 248-248S393 8 256 8 8 119 8 256zm448 0c0 110.5-89.5 200-200 200S56 366.5 56 256 145.5 56 256 56s200 89.5 200 200zm-72-20v40c0 6.6-5.4 12-12 12H256v67c0 10.7-12.9 16-20.5 8.5l-99-99c-4.7-4.7-4.7-12.3 0-17l99-99c7.6-7.6 20.5-2.2 20.5 8.5v67h116c6.6 0 12 5.4 12 12z"></path>
  </symbol>
  <symbol id="arrow-alt-circle-right">
    <path d="M504 256C504 119 393 8 256 8S8 119 8 256s111 248 248 248 248-111 248-248zm-448 0c0-110.5 89.5-200 200-200s200 89.5 200 200-89.5 200-200 200S56 366.5 56 256zm72 20v-40c0-6.6 5.4-12 12-12h116v-67c0-10.7 12.9-16 20.5-8.5l99 99c4.7 4.7 4.7 12.3 0 17l-99 99c-7.6 7.6-20.5 2.2-20.5-8.5v-67H140c-6.6 0-12-5.4-12-12z"></path>
  </symbol>
  <symbol id="calendar-alt">
    <path d="M148 288h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12zm108-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm96 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm-96 96v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm-96 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm192 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm96-260v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48zm-48 346V160H48v298c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"></path>
  </symbol>
  <symbol id="envelope">
    <path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zM403.8 216.9c2.3-1.9 5.8-0.1 5.8 2.8v122.7c0 15.9-12.9 28.8-28.8 28.8h-249.6c-15.9 0-28.8-12.9-28.8-28.8v-122.6c0-3 3.4-4.7 5.8-2.8 13.4 10.4 31.3 23.7 92.5 68.2 12.7 9.2 34 28.7 55.3 28.6 21.4 0.2 43.2-19.7 55.4-28.6 61.2-44.5 79-57.8 92.4-68.2zm-147.8 77.5c13.9 0.2 34-17.5 44-24.8 79.6-57.8 85.7-62.8 104-77.2 3.5-2.7 5.5-6.9 5.5-11.3v-11.4c0-15.9-12.9-28.8-28.8-28.8h-249.6c-15.9 0-28.8 12.9-28.8 28.8v11.4c0 4.4 2 8.6 5.5 11.3 18.4 14.3 24.4 19.4 104 77.2 10.1 7.3 30.1 25.1 44 24.8z"></path>
  </symbol>
  <symbol id="github">
    <path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zM206.7 344.6c0 1.2-1.4 2.2-3.1 2.2-2 0.2-3.4-0.8-3.4-2.2 0-1.2 1.4-2.2 3.1-2.2 1.8-0.2 3.4 0.8 3.4 2.2zm-18.7-2.7c-0.4 1.2 0.8 2.6 2.6 2.9 1.6 0.6 3.4 0 3.7-1.2s-0.8-2.6-2.6-3.1c-1.6-0.4-3.3 0.2-3.7 1.4zm26.5-1c-1.7 0.4-2.9 1.6-2.8 2.9 0.2 1.2 1.7 2 3.5 1.6 1.7-0.4 2.9-1.6 2.8-2.8-0.2-1.1-1.8-1.9-3.5-1.7zm39.5-229.9c-83.2 0-146.9 63.2-146.9 146.4 0 66.5 41.9 123.5 101.7 143.5 7.7 1.4 10.4-3.4 10.4-7.3 0-3.7-0.2-24.2-0.2-36.8 0 0-42 9-50.8-17.9 0 0-6.8-17.5-16.7-22 0 0-13.7-9.4 1-9.2 0 0 14.9 1.2 23.2 15.5 13.1 23.2 35.2 16.5 43.7 12.5 1.4-9.6 5.3-16.3 9.6-20.2-33.5-3.7-67.4-8.6-67.4-66.3 0-16.5 4.6-24.8 14.2-35.3-1.6-3.9-6.7-20 1.6-40.7 12.5-3.9 41.4 16.2 41.4 16.2 12-3.4 24.9-5.1 37.7-5.1s25.7 1.7 37.7 5.1c0 0 28.9-20.2 41.4-16.2 8.2 20.8 3.1 36.8 1.6 40.7 9.6 10.6 15.5 18.9 15.5 35.3 0 57.9-35.3 62.5-68.9 66.3 5.5 4.7 10.2 13.7 10.2 27.8 0 20.2-0.2 45.2-0.2 50.2 0 3.9 2.8 8.6 10.4 7.3 60-19.9 100.7-76.9 100.7-143.4 0-83.2-67.5-146.4-150.7-146.4zm-88.6 206.9c-0.8 0.6-0.6 2 0.4 3.1 1 1 2.3 1.4 3.1 0.6 0.8-0.6 0.6-2-0.4-3.1-1-1-2.3-1.4-3.1-0.6zm-6.5-4.9c-0.4 0.8 0.2 1.7 1.4 2.3 1 0.6 2.2 0.4 2.6-0.4 0.4-0.8-0.2-1.7-1.4-2.3-1.2-0.4-2.2-0.2-2.6 0.4zm19.4 21.4c-1 0.8-0.6 2.6 0.8 3.7 1.4 1.4 3.1 1.6 3.9 0.6 0.8-0.8 0.4-2.6-0.8-3.7-1.3-1.4-3.1-1.6-3.9-0.6zm-6.8-8.8c-1 0.6-1 2.2 0 3.5s2.6 2 3.4 1.4c1-0.8 1-2.3 0-3.7-0.8-1.4-2.4-2-3.4-1.2z"></path> 
  </symbol>
  <symbol id="gitlab">
    <path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200z"/><path d="M106.789 232.748l147.042 191.088-161.152-119.61c-4.457-3.342-6.313-9.097-4.642-14.295zm49.013-113.624c-2.042-5.755-10.21-5.755-12.253 0l-36.76 113.624h85.775zm36.762 113.624l61.267 191.088 61.267-191.088zm227.06 57.183l-18.752-57.183-147.041 191.088 161.152-119.61c4.455-3.342 6.312-9.097 4.641-14.295zm-55.512-170.807c-2.043-5.755-10.211-5.755-12.254 0l-36.76 113.624h85.774z"></path>
  </symbol>
  <symbol id="rss">
    <path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zM198.5 352c0 21.2-17.2 38.4-38.4 38.4s-38.4-17.2-38.4-38.4 17.2-38.4 38.4-38.4 38.4 17.2 38.4 38.4zm105.4 28.4c-5-92.8-79.3-167.1-172.2-172.2-5.5-0.3-10.1 4.1-10.1 9.6v28.8c0 5 3.9 9.3 8.9 9.6 67.1 4.4 120.9 58 125.3 125.3 0.3 5 4.6 8.9 9.6 8.9h28.8c5.5 0 9.9-4.6 9.6-10.1zm86.5 0.2c-5-140.3-117.9-253.8-258.9-258.9-5.4-0.2-9.9 4.2-9.9 9.6v28.8c0 5.2 4.1 9.4 9.3 9.6 114.7 4.7 206.8 96.8 211.5 211.5 0.2 5.2 4.4 9.3 9.6 9.3h28.8c5.4 0 9.8-4.5 9.6-9.9z"></path>
  </symbol>
  <symbol id="tags" viewBox="0 0 640 512">
    <path d="M497.941 225.941L286.059 14.059A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v204.118a48 48 0 0 0 14.059 33.941l211.882 211.882c18.744 18.745 49.136 18.746 67.882 0l204.118-204.118c18.745-18.745 18.745-49.137 0-67.882zM112 160c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm513.941 133.823L421.823 497.941c-18.745 18.745-49.137 18.745-67.882 0l-.36-.36L527.64 323.522c16.999-16.999 26.36-39.6 26.36-63.64s-9.362-46.641-26.36-63.64L331.397 0h48.721a48 48 0 0 1 33.941 14.059l211.882 211.882c18.745 18.745 18.745 49.137 0 67.882z"></path>
  </symbol>
  <symbol id="telegram">
    <path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zM389.6 163.8l-40.6 191.3c-3.1 13.5-11 16.9-22.4 10.5l-61.8-45.5-29.8 28.7c-3.3 3.3-6.1 6.1-12.4 6.1l4.4-62.9 114.5-103.5c5-4.4-1.1-6.9-7.7-2.5l-141.6 89.2-61-19.1c-13.3-4.1-13.5-13.3 2.8-19.6l238.4-91.9c11-4.1 20.7 2.5 17.1 19.3z"></path>
  </symbol>
  <symbol id="user-circle">
    <path d="M8 256C8 119.033 119.033 8 256 8s248 111.033 248 248-111.033 248-248 248S8 392.967 8 256zm72.455 125.868C119.657 436.446 183.673 472 256 472s136.343-35.554 175.545-90.132c-3.141-26.99-22.667-49.648-49.538-56.366l-32.374-8.093C323.565 339.79 290.722 352 256 352s-67.565-12.21-93.634-34.591l-32.374 8.093c-26.87 6.718-46.396 29.376-49.537 56.366zM144 208c0 61.856 50.144 112 112 112s112-50.144 112-112S317.856 96 256 96s-112 50.144-112 112z"></path>
  </symbol>
</svg>

Bisa dilihat, yang membedakan adalah adanya tag <symbol> pada SVG sprite. Tiap tag <symbol> ini digunakan untuk menyimpan sebuah gambar dan memiliki id unik yang nantinya kita gunakan untuk memanggil gambar pada blok <symbol> tersebut.

Jadi sekiranya Anda hendak membuat berkas SVG sprite sendiri, yang harus dilakukan adalah menyalin seluruh tag <path> dari sebuah gambar SVG dan menempatkannya dalam tag <symbol> tersendiri di berkas SVG sprite dengan memberi id yang unik untuk <symbol> tersebut.

Menampilkan ikon dari berkas SVG sprite

Kita dapat menampilkan ikon yang terdapat dalam SVG sprite, misal ikon RSS, dengan menuliskan tag berikut.

<svg viewBox="0 0 512 512" class="svg-nav svg-nav-footer">
  <use xlink:href="/img/svg-sprites.svg#rss"></use>
</svg>

Keterangan ringkas: viewBox adalah letak dan ukuran SVG viewport, class adalah CSS class dan use adalah tautan menuju berkas SVG sprite dan id dari ikon yang akan digunakan.

Jadi, kita menggunakan format letak-berkas/nama-berkas#id-gambar untuk menampilkan ikon. Dari kode di atas, dimengerti bahwa kita menampilkan gambar rss dari berkas svg-sprites.svg yang terletak dalam folder img.

Pengaturan tampilan ikon SVG menggunakan CSS

Pengaturan tampilan ikon lebih lanjut dapat (dan sebaiknya) menggunakan peraturan yang dituangkan dalam berkas CSS.
Misal dalam kode di atas saya gunakan class svg-nav yang mengatur matra ikon dan svg-nav-footer yang mengatur warna ikon.

.svg-nav {
  width: 38px;
  height: 38px;
}

.svg-nav-footer {
  fill:#fdf6e3;
}

So, that’s it. Pastinya ada banyak cara lain untuk menampilkan ikon SVG dari berkas SVG sprite, namun hanya dengan menggunakan tag <use>-lah yang lumayan bisa dibuka di banyak browser. Well, setidaknya Firefox dan Chrome based browsers. Entah jika di Internet Explorer/Edge. Siapa pula yang kini masih menggunakan IE.