Use your custom Bootstrap icons in your Rails apps

This is an archive of blog post I wrote during my third venture (PullReview).

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 60x56 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 15x14: 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 iconicon-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 15x14:

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 intoapp/assets/images/icons for each icon SVG file,
  • a PNG fileapp/assets/images/icons.png containing all the icons packed into one file,
  • a stylesheetapp/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!).


If you have any comment, question, or feedback, please share them with me.


Atom feed icon Subscribe to the blog!