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,
<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 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 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 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!).
If you have any comment, question, or feedback, please share them with me.