Taming icon fonts for use in Rails views

Updated . Posted . Visible to the public.

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 helper trash_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.

Henning Koch
Last edit
Jonas Schiele
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra dev (2012-10-31 10:45)