Icon fonts like Font Awesome are infinitely scalable, look great on high-DPI displays and will give your app a modern look.
However, icon fonts can be very awkward to use compared to raster icons. Elements are given icons by giving them a special class like icon-plus
or icon-home
:
<span class="icon-plus">Create</span>
The icon font's stylesheet will then recognize this class and insert the icon as the element's :before
style.
In practice, this pattern will give you a lot of headaches. This card contains some advice that has helped me to use icon fonts more comfortably.
1 Map the font's icon names into your application domain
You don't want to repeat a 100 times that the icon for a "post" is actually icon-comment-alt
, or that cancel buttons should be decorated with icon-remove
because the shape fits so well.
What I do instead is use helper icon_font_class
that maps concepts from my application domain to classes from the icon font:
module IconHelper
ICONS = {
:close => 'icon-remove',
:email => 'icon-envelope',
:home => 'icon-home',
:post => 'icon-comment-alt',
:user => 'icon-key',
:add => 'icon-plus',
:trash => 'icon-trash'
}
def icon_font_class(icon)
ICONS[icon.to_sym] or raise "Unknown icon: #{icon}"
end
end
2 Use a helper to give additional markup to icon elements
I never set icon font classes directly. Instead I use another helper (icon
) that wraps a HTML snippet with the icon class and some additional markup:
<%= icon(:email, 'Send message') %>
This will produce the following HTML:
<span class="icon icon-envelope">
<span class="label">
Send message
</span>
</span>
You can also use the helper to write an icon without a label:
<%= icon(:email) %>
Advantages of using the helper are:
- All icons get a class
icon
which I can use to style elements that have an icon - Automatic mapping of domain concepts to icon font classes (as described above)
- Icons get their own
<span>
wrapper so elements with icons retain their own:before
slot free for non-icon styles - The icon label is wrapped into its own
<span class="label">
so the label can be styled separately from the icon, e.g. to give it some left margin to the icon. - I also use the extra
<span class="label">
to hide the label in some contexts. E.g. I have a helpertrash_action(record)
which produces a link labelled "Delete" with a dustbin icon. I use this helper in many views, but in the index view I hide the label to better fit the layout.
Here is the helper:
module IconHelper
def icon(*args, &block)
options = args.extract_options!
icon_name, label_or_nil_with_block = args
icon_font_class = icon_font_class(icon_name) # || icon.to_s.dasherize # font awesome uses dashes to separate words
label = block ? capture(&block) : label_or_nil_with_block
custom_class = options.delete(:class)
classes = [icon_font_class, "icon", custom_class].compact
if label.present?
label = content_tag(:span, label, :class => 'label')
end
content_tag(:span, label, options.merge(:class => classes.join(' ')))
end
3 Use a Sass mixin to style icons
When you want to change the style of an icon (e.g. to change its color) you need to use this awkward expression:
.element_with_icon .icon:before {
color: red;
}
Instead I use a Sass mixin to write this:
+icon
color: red
Here is the mixin (requires modern Sass versions):
=icon
.icon:before
@content
4 Add space between icons and their labels
There should be some space between icons and their labels:
.icon
.label
margin-left: 0.3em
Note how the margin is attached to the label so there will be no margin for icons without a label. Also note how I am using em
units so the space will grow or shrink as the font size changes.
Further reading
You can also use FontAwesome icons as Unicode glyphs or HTML entities. Depending on your use case, this might be practical or not.