Skip to content

Instantly share code, notes, and snippets.

@StephanHoyer
Last active August 10, 2023 17:16
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save StephanHoyer/de107b794c43f28ffd75 to your computer and use it in GitHub Desktop.
Save StephanHoyer/de107b794c43f28ffd75 to your computer and use it in GitHub Desktop.
SVG Icons with mithril.js

Icons have been part of applications since ages. Also most websites rely on icons. There were several ways to use them. First we used plain files then image sprites to reduce requests. Nowadays everyone uses icon fonts like font-awesome or glyphicons.

They are infinetly scaleable and styleable with css. The downside is they use pseudo elements for displaying. This is not only difficult to handle but also non-optimal for accessibilty.

A famous CSS-Tricks post brings SVG icons into play. The are also scalable and they behave like normal images. But we also want to have a sprite to not load any images seperatly and kill our servers and our sites performance. The proposed version is to create sprites with grunt or gulp using the symbol-trick. It's basically add every icon to a hidden sprite-image and give every icon an id-property.

<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  
  <symbol id="beaker" viewBox="214.7 0 182.6 792">
    <!-- <path>s and whatever other shapes in here -->  
  </symbol>
  
  <symbol id="shape-icon-2" viewBox="0 26 100 48">
    <!-- <path>s and whatever other shapes in here -->  
  </symbol>
  
</svg>

Then you can do this

<svg class="icon">
  <use xlink:href="#shape-icon-1" />
</svg>

This is a pretty clever idea if you don't have a framework like mithril. You still have the burden to create svg-sprites and you have to have on hidden element that holds the icons (which is no really problem, but verbose)

If you use browserify and mithril (what I strongly entourage you to do) there is an even simpler way. Browserify lets you include any file you want and base64 encodes them into the build. So first put your icons in a directory of your choice. Then you create a module called icons.js:

var fs = require('fs');
var m = require('mithril');

function icon(svg) {
  return m('.icon', m.trust(svg));
}

module.exports = {
  icon0: icon(fs.readFileSync('directory_of_your_choice/icon0.svg', 'utf8')),
  icon1: icon(fs.readFileSync('directory_of_your_choice/icon1.svg', 'utf8')),
  icon2: icon(fs.readFileSync('directory_of_your_choice/icon2.svg', 'utf8'))
};

Browserify spots these files are read with fs.readFileSync loads them as Base64-encoded strings. The module then creates a div with class icon and embeds the svg into that div. The m.trust function prevents the svg from beeing html-encoded.

Now you have a module with all your icons in it. To use them simply embed them into your view functions:

var icons = require('./icons');

function myView(scope) {
  return m('.content', [
    icons.icon1
    'My fancy icon div'
  ]);
}

The output then looks something like this

<div class="icon">
  <svg>
    <!-- <path>s and whatever other shapes in here -->
  </svg>
</div>

Pay attention to use the brfs-transform along with browserify. This embeds the readFileSync-ed files.

browserify -t brfs index.js

The advantages of this usage are:

  • No building svg sprites
  • Advantages of SVG over Fonts (better handling and styling)
  • One less file, since the icons are embedded in your javascript file
  • Easy to maintain
  • Minimal code
  • Pretty output
  • Mithril-way of doing things :)
@limdauto
Copy link

limdauto commented Dec 1, 2015

👍 I'm gonna try this tomorrow. This is very clever.

@ArthurClemens
Copy link

mmsvg uses the same method to embed SVG files, but generates js files for easy (ad hoc) inclusion.

@StephanHoyer
Copy link
Author

Added encoding parameter to readFileSync so that browserify don't have to encode this to base64 strings

@connelevalsam
Copy link

connelevalsam commented Nov 13, 2017

i have this:

<div class="bg-white tc pv2">
    <svg version="1.1" width="74px" height="74px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 612 612" style="enable-background:new 0 0 612 612 fill:green; padding: 20px;" xml:space="
    <path d="M21.474,377.522V117.138c0-14.469,11.729-26.199,26.199-26.199h260.25c14.469,0,26.198,11.73,26.198,26.199v260.385
	c0,4.823-3.909,8.733-8.733,8.733H30.207C25.383,386.256,21.474,382.346,21.474,377.522z M231.634,466.724 
c0,30.01-24.329,54.338-54.338,54.338c-30.009,0-54.338-24.328-54.338-54.338c0-30.011,24.329-54.338,54.338-54.338
									C207.305,412.386,231.634,436.713,231.634,466.724z M204.464,466.724c0-15.005-12.164-27.169-27.169-27.169
									s-27.17,12.164-27.17,27.169s12.165,27.17,27.17,27.17S204.464,481.729,204.464,466.724z M130.495,412.385H8.733
									c-4.823,0-8.733,3.91-8.733,8.733v26.495c0,4.823,3.91,8.733,8.733,8.733h97.598C108.879,438.862,117.704,423.418,130.495,412.385z
									 M515.938,466.724c0,30.01-24.329,54.338-54.338,54.338c-30.01,0-54.338-24.328-54.338-54.338
									c0-30.011,24.328-54.338,54.338-54.338C491.609,412.385,515.938,436.713,515.938,466.724z M488.77,466.724
									c0-15.005-12.165-27.169-27.17-27.169c-15.006,0-27.169,12.164-27.169,27.169s12.164,27.17,27.169,27.17
									S488.77,481.729,488.77,466.724z M612,421.118v26.495c0,4.823-3.91,8.733-8.733,8.733h-70.704
									c-5.057-34.683-34.906-61.427-70.961-61.427c-36.062,0-65.912,26.745-70.969,61.427H248.261
									c-2.549-17.483-11.373-32.928-24.164-43.961h134.994V162.594c0-9.646,7.82-17.466,17.466-17.466h82.445
									c23.214,0,44.911,11.531,57.9,30.77l53.15,78.721c7.796,11.547,11.962,25.161,11.962,39.094v118.672h21.253
									C608.09,412.385,612,416.295,612,421.118z M523.408,256.635l-42.501-60.393c-1.636-2.324-4.3-3.707-7.142-3.707H407.47
									c-4.822,0-8.733,3.91-8.733,8.733v60.393c0,4.824,3.91,8.733,8.733,8.733h108.798C523.342,270.394,527.48,262.421,523.408,256.635z
									"/>
	</svg>
<div class="ws-normal ph2">
	<span class="measure mw3">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmodtempor incididunt ut</span>
</div>
</div>

and it's not working

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment