ARIA compliant breadcrumbs
I've been looking at improving accessibility across my main website. One of my main goals when building it originally was to keep it as simple as possible, which is now paying off as I begin to make changes. Despite keeping it simple, I did still want the site to have at least some character, to have a little bit of me in it. So I went with the not so unique approach of styling parts of the site to look like terminal output, such as my main site navigation. I used a breadcrumb navigation and styled it to look like a directory path in a terminal prompt.
After some reading and research, I concluded that my breadcrumb nav had an issue. There was decorative text in there that was of no value to the user, and would likely cause issues for anyone using a screen reader or other accessible technology.
You might notice I am putting line breaks in odd places in my markup, this is because a line break in HTML is considered equal to one character-width of white space, and I didn't want my text flying off the right hand side of my screen (I don't wrap my code editors).
<header>
<nav class="breadcrumbs">
<span class="host"><a href="/">aaronwatts@dev</a></span>:<span
class="path">/<a href="/guides">guides</a>/firefox-web-apps $</span>
</nav>
</header>
Furthermore, after browsing the ARIA guidance pages, I discovered that there is a recommended pattern for breadcrumb navigation:
<nav aria-label="Breadcrumb" class="breadcrumb">
<ol>
<li>
<a href="../../../..">
WAI-ARIA Authoring Practices Guide (APG)
</a>
</li>
<li>
<a href="../../../">
Patterns
</a>
</li>
<li>
<a href="../../">
Breadcrumb Pattern
</a>
</li>
<li>
<a href="" aria-current="page">
Breadcrumb Example
</a>
</li>
</ol>
</nav>
I have also recently redesigned the hero for my site's home page to:
- Hide decorative text from the cursor (i.e. no highlight/copy)
- Hide decorative text from ARIA technology
I achieved this by applying CSS ::after pseudo elements to spans marked as aria-hidden. I may have been okay just using ::after pseudo elements, but there was a little debate on StackOverflow as to whether or not this is definitely hidden from the accessibility tree or not.
<header>
<div class="hero">
<span class="hero-text">
<h1><span class="host">aaronwatts@dev</span></h1><span
aria-hidden="true" class="term-dir" /></span><span
aria-hidden="true" class="term-priv" /></span><span
aria-hidden="true" class="term-cursor" /></span>
</span>
</div>
</header>
.hero span.term-cursor::after {
content: ' █';
}
.term-priv::after {
content: ' $';
}
.hero .term-dir::after {
content: ':~';
}
So, in accordance with the ARIA pattern for breadcrumbs, I have rewritten by navigation to be an ordered list, ready to be styled to look like a terminal prompt, while hiding any decorative text from the main tree. I am also still breaking my lines in weird places to preserve white space. While redesigning this, I learned that href="" is equivalent to href="#", but differs only in the sense that the former doesn't add an entry to the history object whereas the latter does.
<header>
<nav aria-label="Breadcrumb">
<ol>
<li><a
href="/">aaronwatts@dev</a></li><span
aria-hidden="true" class="term-dir"></span><li><a
href="/guides/">guides</a></li><li><a
href="" aria-current="page">appsheet</a></li><span
aria-hidden="true" class="term-priv"></span>
</ol>
</nav>
</header>
With some fancy pants CSS selectors and nesting, I got things looking the way I wanted. It's moments like this when I feel like I'm finally getting the hang of CSS, everything just kind of worked first time. I wish that were the case all the time.
nav[aria-label='Breadcrumb'] {
font-family: JetBrainsMono;
font-size: .9rem;
font-weight: bold;
letter-spacing: .09rem;
box-sizing: border-box;
& ol {
list-style-type: none;
padding: 0;
}
& li {
display: inline;
& a {
text-decoration: none;
color: var(--accent-secondary);
&:hover {
color: var(--accent-secondary-light);
}
}
}
& li:first-of-type a {
color: var(--accent-primary);
&:hover {
color: var(--accent-primary-light);
}
}
& li:not(li:first-of-type)::before {
content: '/';
color: var(--accent-secondary);
}
& .term-dir::after {
content: ':';
}
}
.path,
.term-priv {
color: var(--accent-secondary);
}
.term-priv::after {
content: ' $';
}