Dusted
Codes

Programming Adventures

Making Font Awesome awesome - Using icons without i-tags

Published

Comments

font-awesome css

Font Awesome is truly an awesome library. It is widely used across many websites and has made a web developer's life so much easier!

There is one thing which I don't find that awesome though. It pollutes your HTML with a lot of styling markup.

Let me explain the problem with an example...

The Problem

The default way to include an icon into your website is by adding an <i> tag into your HTML code; like this:

<i class="fa fa-car"></i>

For example, the car icon will render into:

This is great, but now you end up with many empty <i> tags in your HTML code, which have no structural purpose in the document whatsoever. Even worse, these tags are tightly coupled to a concrete theming technology, Font Awesome in this case.

This is not great and I personally think HTML markup should be theme agnostic.

Solutions out in the wild

A quick Google search brought up some solutions to the problem. None of them without any drawback though.

#1 Shipping a modified copy of Font Awesome

By providing your own copy of Font Awesome you'd obviously be able to do what you like and easily solve the problem, however this appraoch has some major issues:

  1. I don't want to maintain a custom copy of Font Awesome
  2. The library is quite big and I really want to benefit from the public CDN

#2 Add the classes to the target element

The next best suggestion was to attach the classes to the target tag instead of the <i> tag.
For example:

<a class="fa fa-car" href="#">This is a link</a>

Result:
This is a link

As you can see this works, but Font Awesome has become the font for the entire anchor tag now. The browser ends up rendering the text in the default font, which mostly comes from the serif family and is rarely what you want.

#3 Setting the unicode character in your custom CSS

The most popular solution was to set the Unicode character for the content property of the ::before attribute:

a:before {
    font-family: FontAwesome;
    content: "\f1b9";
    display: inline-block;
    padding-right: 3px;
    vertical-align: middle;
}

The result will be visually perfect, but there are a few things which I don't like about this appraoch:

  1. I have to add custom CSS for each tag which I want to decorate
  2. The unicode character can change
  3. It is not readable! CSS code is still code and deserves the same best practices like any other code

Analysing the Font Awesome CSS classes

After I wasn't really satisfied with any of the proposed solutions I tried to find a better one.

Let's break it down

Each icon consists of two CSS classes - the shared "fa" class and an icon-specific class like "fa-car". Setting only the icon-specific class will result in a not very meaningful unicode character:

<a class="fa-car" href="#">This is a link</a>

Result:
This is a link

The icon isn't what we want, but at least the tag's original font remains as is. Using the Google Chrome developer tools I can quickly confirm that the icon-specific class is not doing any harm to the original tag:

CSS source code of the Font Awesome car icon, Image by Dustin Moris Gorski

Evidently this class only adds the content to the ::before attribute of the target element. The conclusion is that the actual styling gets applied via the "fa" class:

CSS source code of the Font Awesome fa class, Image by Dustin Moris Gorski

Now this makes sense. The content from the ::before attribute gets rendered inside the original tag and therefore also picks up the styling from the fa class.

Everything from the fa class could equally go into the icon class as part of the ::before attribute, but I can see why the Font Awesome team has extracted it into a shared class, because it is the same for every icon and would be otherwise a maintenance nightmare.

The ultimate solution (or at least the best I came up with)

After inspecting the code I realised that all I need is to create one additional class in a custom style sheet to fix the problem:

.icon::before {
    display: inline-block;
    margin-right: .5em;
    font: normal normal normal 14px/1 FontAwesome;
    font-size: inherit;
    text-rendering: auto;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    transform: translate(0, 0);
}

It is a copy-paste of the original fa class with 3 changes to it:

  1. I named the class "icon" to avoid a conflict
  2. I attached the ::before attribute
  3. I added a small margin-right, so that the icon doesn't stick to the original tag

With this little trick it seems like I am able to tick all the boxes:

  • I can continue to use the original Font Awesome CDN library
  • I don't need to add empty i-tags
  • It doesn't interfere with other CSS on targeted elements
  • I don't have to make a custom CSS change for each individual icon (unlike the unicode appraoch)
  • The code is readable!

Now it can be used like this:

<a class="icon fa-car" href="#">This is a link</a>

Result:
This is a link

Especially the fact that I don't have to use the unicode characters is very appealing. When I read the code "icon fa-car" it is pretty obvious what the rendered result will look like.

Conclusion

At the moment I haven't found a drawback with this appraoch, but there might be something which I have overlooked. If you know of any issues or if you know an even better appraoch, then please let me know! Feedback is much appreciated!