I’ve been playing around with loading spinners (not fidget spinners) recently and wanted to investigate how to make a spinner that is accessible to the widest range of users.
Optimizing for screen readers
At first, I wanted to ensure that users that had a screen reader could understand that the page was loading without the need to encounter the loading spinner. This was achieved by using a piece of “screen reader only” text that alerts when the loading spinner appears. This text will be reused later when we talk about reduced motion.
Second I made sure that the spinner was hidden from the screen reader. It uses css content which can be announced in some screen reader. Hiding the spinner is acheived with the aria-hidden=”true” attribute.
Optimizing for High Contrast
I tried using the -ms-high-contrast media query to only add CSS properties when the system high contrast mode was active. Unfortunately, the only browsers that supported it were Edge and IE11. This meant that highly used browsers like FireFox
One common technique that is used for the dot spinners is to make the CSS background of each dot the color that is desired. The problem with using the background is that it is removed in high contrast mode. This typically renders the spinner invisible.
One thing that doesn’t disappear in high contrast mode is the css border property. I utilize this property to ensure that the dots are visible even when the background is not. This has the unfortunate effect of making the dots even larger. The way to ensure that the dots remain the desired size is to set the CSS box-sizing to “border-box”. This will make the border expand “into” the content instead of adding to it’s size.
Optimizing for Reduced Motion
This is where it started getting fun for me. CSS Media Queries Level 5 is still a working draft, but the prefers-reduced-motion query is already widely supported by browsers. So as a way to progressively enhance the control for people with distractability (e.g. ADHD) or Vestibular disabilities it is a great option.
I use the prefers-reduced-motion query to do two things. First, I remove all motion from the page. This works well for animations, like parallax. In the case of the spinner, it just made it look like a little worm on the page. It looks like a snake.io game or something similar.
This triggered the second improvement from the prefers-reduced-motion. Do you remember that “Loading…” text that we added for screen readers only? Well, that’s going to become very useful for the next technique. When a user has their reduced animation or reduced motion settings on their device enabled it sets the systems prefers-reduced-motion setting. We can leverage this with our CSS.
Using the media query, we can hide the spinner “snake” and then we can show the screen reader only text instead. The spinner is hidden with the CSS display:none and we add CSS to make the screen reader only text visible again.
I have set up a codepen to demo this technique. If you want to see it in action, follow the instrucitons in this iframe