Read more

Taming icon fonts for use in Rails views

Henning Koch
October 31, 2012Software engineer at makandra GmbH

Icon fonts like Font Awesome Show archive.org snapshot are infinitely scalable, look great on high-DPI displays and will give your app a modern look.

Illustration UI/UX Design

UI/UX Design by makandra brand

We make sure that your target audience has the best possible experience with your digital product. You get:

  • Design tailored to your audience
  • Proven processes customized to your needs
  • An expert team of experienced designers
Read more Show archive.org snapshot

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
October 31, 2012Software engineer at makandra GmbH
Posted by Henning Koch to makandra dev (2012-10-31 11:45)