Writing HTML is about more than simply “having stuff appear on the page.” Each element you use has a meaning and conveys information to your visitors, especially to those that use assistive technologies to help interpret that meaning for them.
A majority of a site’s visitors will be able to use their sight to help them understand what things are and what they might do. For them, it’s largely irrelevant that the thing that looks like a button isn’t built with a <button>
element. As long as it functions in a way that matches their goals and expectations, they will be happy (maybe even delighted if it does exceptionally well).
But what if you couldn’t see the page for yourself and you need assistive technology to help you? Suddenly, all the inherent semantic information that HTML elements carry becomes infinitely more relevant.
This post will describe three examples where semantics matter and how they may influence a user’s experience on the website.
Anchors, and buttons, and spans, oh my.
It’s entirely possible to add a span or a div to a page, slap some CSS and JS on it, and call it a button. Maybe you’d do it because it’s “easier” to make it look like the design that way. Or, maybe you have a different reason for doing this. However, you’d only be doing yourself a disservice by reinventing the wheel and making a bunch of extra work for yourself.
You see, it may look like a button. It may even act like a button when you click it. What it most likely won’t do is get added to the page’s list of focusable elements. This means that people navigating your site with a keyboard will never be able to reach it, let alone interact with it.
And, I can almost guarantee that it won’t identify as a button either. This is an important detail to those that use assistive technologies to tell them what something is. If I don’t even know it’s a button, then how can I be expected to know that I can interact with it?
Both of these shortcomings can be fixed to some extent, but why would you? The browser will take care of all of these things for you when you use the appropriate element, and it will do that much better than you can emulate them. As a bonus, you’ll be supporting older browsers without even trying!
In addition, both the anchor and button element have a number of additional attributes that are simply not valid to use with a div or a span – attributes with which you can give more information, or with which you can instruct the browser how to handle it.
For example, if I were to add the download
attribute to a link, I can basically tell your browser to download the file I’m linking to instead of trying to open it. I can also add more information about the page I’m linking to through attributes like rel
or hreflang
.
Or, you can use the disabled
attribute on a button element, which will allow you to easily disable it completely. A button that is disabled this way cannot get focus anymore, nor can it be activated anymore. For all intents and purposes, it does not exist anymore. Simply removing this state attribute will completely restore the button’s function again.
The subtle difference between anchors and buttons
A more common occurrence is anchor tags acting like buttons. While this isn’t necessarily as bad, you’d still be using an element whose primary function is relating documents (or sections of the same document) together to do something it wasn’t meant to do.
So how can you easily recognize when to use an anchor and when to use a button? If you are using a valid href
attribute to link to a different page, or to a different section on the same page, then go right ahead and use an <a>
tag.
Otherwise, every time you find yourself writing a toggle that is along the lines of one of the following, you may want to consider using a <button>
instead:
<a href="#" id="click-this">Click Me, I do stuff</a>
<a href="javascript:toggleStuff();">No, click me. I do stuff too!</a>
Always remember, someone using a screen reader doesn’t really care what the thing looks like. All they will know is what their screen reader tells them about the thing, and that will come down to two simple words that carry a lot of implied meaning: “link” or “button.”
Headings, more than just text size
The headings (<h1>
–<h6>
) in your document provide for more than simply a way to increase the size of the text. It’s true that, visually, headings will stand out in most cases and do their job that way.
But remember, not everyone will be able to see your page. Headings have the added benefit of making an outline of your document available. They allow you to give a good overview of what the page is going to be about. Additionally, most screen readers allow their users to jump through the page from heading to heading. In this specific situation, your heading is now without any context and needs to convey what the section is going to be about by itself. And so, those sentences that are marked up with different heading levels become meaningless fractures.
For a good illustration of how navigating a page with headings works, have a look at this video:
Form elements
Forms, too, benefit from being structured semantically. Just like spans that were turned into buttons, your users will also stop liking you if you do not use form fields appropriately.
And like anchors and buttons, each form element (and especially more complicated ones, such as select boxes) come with inherent functionality based on the browser’s implementation. To stay on the select box example, this element lets you select an option with the arrow keys but will also allow you to select an option through typing. That is to say, typing “united s” in a list of countries will select “United States of America” for you. Screen readers will also read out every option as you navigate through the list with the arrow keys.
With all this in mind, it’s all the more heartbreaking to see form widgets that are aimed to replace these native elements for something that looks nicer or that has more functionality and do a poor job at it. It is really easy to forget about all the other things that these elements do for your users. And at the same time, it can be really complicated to get it to work well, too.
To illustrate, I’ve prepared a video straight from the demo page for one of these libraries that “enhances” form elements (it is irrelevant which one it is, really). It demonstrates how a regular select box element works in Chrome with NVDA running. As you’d expect, it reads out the options properly. The “enhanced” version, on the other hand, continuously reads out “blank,” at least until I try and filter the list by typing some letters, because then it starts repeating what I’ve typed instead.
But my feature needs some control that doesn’t even exist!
By now I can hear you think: “That’s great and all, but my needs surpass what native elements can provide.”
Awesome! By all means, use whatever elements you think are appropriate for your cool feature. But, don’t forget that you’re now responsible for making it accessible, too.
So, make sure you have a clear vision of the following:
- What goal does it have and how does it do that better than other options?
- How should it operate with a mouse?
- How should it operate with a keyboard?
- How does it manage focus states (which is especially important for more complicated widgets, like calendars, for example)?
- What kind of feedback should it give the user?
- And finally, what does it actually do when a user decides to use it?
And then make sure to read into WAI-ARIA, because this is exactly what a use-case WAI-ARIA is for.