Use your custom Bootstrap icons in your Rails apps

Twitter Bootstrap offers a great set of icons provided by Glyphicons that you can use easily in your pages. For instance, icon-ok

<i class="icon-ok"></i>

If you don’t like those icons, you can use Font Awesome instead of.

But how can you use other icon sets or even your own icons in your Rails app with the same facility?

<i class="myicon-great"></i>

I’ll present you a solution based on the gems sprite-factory and bootstrap-sass. It requires your icons to follow a precise specification, a custom stylesheet and a Rake task to generate them.

The icon specification

The icon dimensions are 60×56 and stored as a SVG file myicon.svg in the directory app/assets/images/icons/. When drawing the icon, try to keep in mind that the icon dimensions will be reduced to 15×14: draw everything as a multiple of 4.

The stylesheet

The technique of CSS sprites allows you to gather all background images in a single file. You then display only the part you want with a clipping rectangle defined by the dimensions of your block element and the background position. Twitter Bootstrap provides all the icons as is. If you look into the sass-bootstrap stylesheet defining the icons class, you’ll find three important parts:

  • the common properties to all icon classes [class^="icon-"], [class*=" icon-"],
  • the properties for inverted icon icon-white, and
  • a sprite for each icon, for instance .icon-glass { background-position: 0 0; }.

For our own icons with a class name starting with myicon-, we’ll do the first and last part (no inverted version). The properties common to all icons are the following:

app/assets/stylesheets/_mysprites.scss

[class^="myicon-"], [class*=" myicon-"] {
  display: inline-block;
  width: 15px;
  height: 14px;
  line-height: 14px;
  vertical-align: text-top;
  background-image: url('icons.png');
  background-position: 15px 14px;
  background-repeat: no-repeat;
  margin-top: 0;
  vertical-align: text-bottom;
}

For the last part defining the CSS sprites themselves, we’ll use sprite-factory.

The generation

The gem sprite-factory will help you to pack all icons in one file and generate the corresponding CSS sprites. It can even be used in a Rake task.

First write the dedicated Rake task

lib/tasks/resprite.rake

require 'sprite_factory'

namespace :assets do
  desc 'recreate sprite images and css'
  task :resprite => :environment do
    # your task that we'll describe below
  end
end

As we have icons as SVG files, I add first a command using the magic convert command of ImageMagick to transform them into PNG files with dimensions of 15×14:

lib/tasks/resprite.rake

# ...
Dir.glob('app/assets/images/icons/*.svg').each do |svg_file|
  %x(convert -antialias -background transparent #{svg_file} -resize 15x14 #{File.dirname svg_file}/#{File.basename(svg_file).gsub(/\.svg\z/, ".png")} )
end
# ...

Then, I set up sprite-factory to use sass-rails helper method image-url to be evaluated by the rails asset pipeline:

lib/tasks/resprite.rake

# ...
SpriteFactory.cssurl = "image-url('$IMAGE')"
# ...

I define an array rules of CSS directives that will be used by sprite-factory to generate the stylesheet, and already append to it the definition of common properties to all classes myicon-:

lib/tasks/resprite.rake

# ...
rules = []
rules << <<EOF
[class^="myicon-"], [class*=" myicon-"] {
  display: inline-block;
  width: 15px;
  height: 14px;
  line-height: 14px;
  vertical-align: text-top;
  background-image: url('icons.png');
  background-position: 15px 14px;
  background-repeat: no-repeat;
  margin-top: 0;
  vertical-align: text-bottom;
}
EOF
# ...

Finally, I run sprite-factory with some parameters

lib/tasks/resprite.rake

# ...
SpriteFactory.run!(
  'app/assets/images/icons',
  :style => :scss,
  :layout => :packed,
  :library => :chunkypng,
  :selector => '.myicon-',
  :output_style => 'app/assets/stylesheets/_mysprites.scss',
  :nocomments => true
) do |images|
  images.map do |name, data| # for each image, we add a CSS sprite
    rules << ".myicon-#{name} { background-position: -#{data[:x]}px -#{data[:y]}px; }"
  end
  rules.join("\n")
end
# ...

Get the final result at that Gist.

The usage

As everything is set up, I can use my Rake task as

rake assets:environment

It generates:

  • a PNG file into app/assets/images/icons for each icon SVG file,
  • a PNG file app/assets/images/icons.png containing all the icons packed into one file,
  • a stylesheet app/assets/stylesheet/_mysprites.scss

We can now enjoy it by importing it into the application stylesheet:

@import 'mysprites';

You have no more reason to not go create yours! If you do, let me know (and if we can see them on a page, even better!).





One thought on “Use your custom Bootstrap icons in your Rails apps

  1. Pingback: Code Rules are Lines, not Walls | 8th color

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>