#15DaysOfCSS Day 11: Accessible icons in navbars


🎉📚Get the #15DaysOfCSS e-book📚🎉

These #15DaysOfCSS posts will be compiled into an e-book — pre-order now!

Email is great, and blogs are awesome, but it can be challenging to use them as a reference in the future. We'll be assembling this month's work into an e-book.

Pre-order the book

Font Awesome is one of the most popular fonts on the web. With over 1600 free icons and over 7800 paid icons, they have an icon for any situation you might imagine.

Indeed, with its incorrect choice of markup for including the icons using the <i> element, it's easy to tell how popular Font Awesome has become. The HTTP Archive's 2020 report shows that <i> is the 9th most popular element on the web. Not bad for an element that was completely deprecated in HTML4 and had little use in HTML5, until Font Awesome came along.


Historically, <i> stood for italic, as in "make this text italic." It dates back to the mid 1990s when we had no other options for making text bold (<b>) or italic (<i>) without these elements — CSS was not supported by browsers at this time.

These elements were deprecated when CSS became more available to use, and they were tossed in the 😠Dustbin of Frowned Upon Elements😠 for many years. <i> found new life in HTML5 as the "idiomatic text element." MDN provides the following explanation:

The <i> HTML element represents a range of text that is set off from the normal text for some reason, such as idiomatic text, technical terms, taxonomical designations, among others. Historically, these have been presented using italicized type, which is the original source of the <i> naming of this element.

None of that has anything to do with icons. That is why we say that Font Awesome is using the <i> element incorrectly. A better choice would be <span>. Our examples use <span> accordingly.

We now return you to #15DaysOfCSS...

Avoiding Mystery Meat Navigation

As Jen was writing her first web pages, she became a huge fan of Vincent Flanders and Web Pages That Suck. She has both books (with CDs!) on her shelf to this day.

Vincent Flanders identified and named Mystery Meat Navigation, or MMN, in the early web days. In the late 1990s and early 2000s, there was an odd trend with designers who decided that navigation was BORING and it needed to be made CONFUSING.

Mysterious icons for navigation were one of the most popular ways to do this at the time. (The video is a bit extreme, in that there's animation in addition to no labels on the nav items, but you get the idea.) The argument went that when someone rolled their mouse over the mysterious link, the URL would show in the corner of the browser, so OF COURSE you knew where you were going.

There is nothing fundamentally wrong with using icons in your navigation, provided the following conditions are met:

  • There's a text equivalent next to the icon, so everyone knows what it means. The text should always be visible, not just on hover. No one knows what most icons mean unless they come with a label.

  • EXCEPTION: The icon is so recognizable, it doesn't need a (visible) text equivalent. Often these are social media icons from the biggest platforms only, and that's about it.

  • BIG CLICKABLE AREAS are not compromised.

  • And of course, your icons must be accessible. That means we need to wrangle some type of text equivalent, even if that text equivalent isn't necessarily visible.

Where to get icons

Icon fonts like Font Awesome and Iconic are incorporated in your website like a font. Use their provided codes to get the icon of your choice to appear. The downside is that a font may have longer load times than individual pictures.

That's where SVGs come in. Font Awesome and Iconic offer these as well, available for download individually, or you can get these at The Noun Project and many other sites. Or draw your own using programs like Adobe Illustrator or other vector-based drawing tools, then export in SVG format.

Setting up Font Awesome in CodePen

Follow along with today’s CodePen example

We will use Font Awesome in CodePen, because it's easily accessed and easy to set up. In your pen, go to Settings - CSS, scroll to External CSS, type Font Awesome in the search box, and you'll find a link to the free version of the font.

Once the font is installed, to find the icons of your choosing, go to Font Awesome's website and type "Twitter" in the search bar. The search results will give you several icon choices. Choose one of the free results and copy the HTML by clicking on the code fragment. For example, I'm using twitter-square:

<i class="fab fa-twitter-square"></i>

Let's repeat that process for Facebook and LinkedIn, to generate a set of three icons. We'll mark these up as an unordered list with links, so the end result is this:

  <h2>Follow Jen Kramer on social media</h2>
    <li><a href="https://twitter.com/jen4web"><span class="fab fa-twitter-square"></span></a></li>
    <li><a href="https://facebook.com/webdesignjen"><span class="fab fa-facebook-square"></span></a></li>
    <li><a href="https://linkedin.com/in/jen4web"><span class="fab fa-linkedin"></span></a></li>

Did the <address> element throw you? From MDN:

The contact information provided by an <address> element's contents can take whatever form is appropriate for the context, and may include any type of contact information that is needed, such as a physical address, URL, email address, phone number, social media handle, geographic coordinates, and so forth. The <address> element should include the name of the person, people, or organization to which the contact information refers.

We think <address> is a better fit to this navbar of social media links for contact information, over <nav>, which indicates major navigation. In either case, it is an unordered list of social media profiles. The heading above it contains Jen’s name, filling the requirements for the <address> element.

As mentioned earlier, we also changed <i> elements to <span> elements.

Make it accessible

Follow along with today’s CodePen example

Facebook, Twitter, and LinkedIn are recognizable icons to those who would use social media. However, these icons are not accessible. There is no text equivalent for each icon anywhere, and the icons are unlabeled.

Fixing them won't take long, and it makes a huge difference to many people. Here's our approach (showing a single list item):

      <a href="https://twitter.com/jen4web">
        <span class="fab fa-twitter-square" aria-hidden="true"></span>
        <span class="sr-only">Twitter</span>

First, we hid the icons from screen readers with the attribute aria-hidden="true". This means screen readers will ignore the icon and not try to read it.

Second, the class of sr-only stands for "screen reader only." This class is part of the Font Awesome stylesheet, which loads as part of your call to the Font Awesome font itself. This particular class also shows up in tons of frameworks like Bootstrap, Tailwind, and others.

Frequently, this class looks like this:

.sr-only {
   position: absolute;
   width: 1px;
   height: 1px;
   padding: 0;
   margin: -1px;
   overflow: hidden;
   clip: rect(0,0,0,0);
   border: none;

It contains a bunch of browser fallbacks such that it hides the text from view in the browser window, but preserves the text so that a screen reader may read it. The <span> element is an inline element that serves to hold the class around our text.

Font Awesome has other suggestions for making their font and SVG icons accessible on their website.

The final navbar looks as you’d expect:

🤯 Time to blow your minds 🤯

We've given you a second example of icon-based navigation today:

This is the same approach as the first navigation bar, with two differences. First, this bar is major navigation, and it’s wrapped in a <nav> element. Second, we're allowing the label to display for our (meaningless) icons. The real question is how did we get the icon to stack on top of the text? As always, the answer is with parents and children, and that starts in the HTML:

      <a href="#">
        <span class="fas fa-phone-square" aria-hidden="true"></span>

The <a> element has two children, both <span> elements. We set <a> to be our Flexbox container (parent), while the <span> elements are the items (children), then stack the icon on top of the text and center it.

.example1 a {
  display: flex;
  flex-flow: column nowrap;
  justify-content: center;
  align-items: center;
  color: #8854d0;

That means we have Flexbox controlling the overall navbar layout in a row via <ul> and <li>, and then we have a second round of Flexbox columns with the <a> and <span> elements. Totally legal! Super cool!

The rest of the CSS is available in today's CodePen example.

🖥 Today’s CodePen example

Today’s CodePen example maps out the code described in this email.

View today's CodePen example

👩🏽‍💻 Challenge: Accessible icons in navbars

👩🏽‍💻 In today’s challenge, make a navbar with accessible icons for the four elements, Earth, Air, Water, and Fire.

Take today's CodePen challenge

📚 More information and examples

📚 CSS Tricks: How Can I Make My Icon System Accessible?

📚 NNgroup: Bad Icons: How to Identify and Improve Them

📚 Font Awesome accessibility

📚 A11y-101: Icons and Links

📚 MDN: <i>: The Idiomatic Text element

📚 MDN: <address>

📽 LinkedIn Learning: HTML and CSS Creating Navigation Bars (subscription required)

📽 Flexbox and Grid version 2 at Frontend Masters (subscription required)