How to Accessibly Rotate Contents with jQuery

Together with the parallax scrolling effect, rotating content is another example of an effect that you often see implemented in websites. You can see it used to rotate news, tweets, Facebook posts, and so on. When built using jQuery, often developers create the widget employing the hide() and the show() methods (or the similar methods such as fadeIn()/fadeOut() and slideUp()/slideDown()). The problem with them is that, after performing the animation (if any), these methods change the value of the display property of the selected element(s) to none and back to the original value respectively. This behavior leads to an accessibility issue.

In this article we’ll describe what the issue is and how you can use different jQuery’s methods to achieve the same effect but taking care of accessibility.

The Problem

Some people, usually but not limited to visually impaired people, use the TAB key to navigate a website. If you’re not familiar with this concept, what happens is that every time a user hit the TAB key a focusable element of the page is focused. The order in which the elements are focused follows the the order they appear in the DOM (exceptions apply) starting from the very beginning of the page. Some examples of focusable elements (learn more in When Do Elements Take the Focus?) are links, input fields, buttons, and everything that has a value for the tabindex attribute greater than or equal to 0 (learn when and how to use tabindex). The important point to understand is that an element hidden by setting its display property to none is not focusable.

With this in mind you can see that if a TAB user is focusing an element (for example a link) that has been hidden using the hide() method and then the user presses the TAB key, there is a problem. Being hidden in that way is like the element has been temporarily removed from the DOM, so there isn’t a next element to focus. What browsers do in this case is to reset the position, usually focusing the URL of the page. This causes a lot of frustration to the users because they have to start from the beginning of the page every time they reach this death zone. Even more, some of your users can’t even see your awesome rotating effect – all they want to do is access your content easily.

Show Me the Code

To give you a better handle on this situation, consider the following markup:

<div class="rotating-content">
   <p>This is a text with a <a href="#">link 1</a> and <a href="#">another link 1</a></p>
   <p>This is a text with a <a href="#">link 2</a> and <a href="#">another link 2</a></p>
   <p>This is a text with a <a href="#">link 3</a> and <a href="#">another link 3</a></p>
   <p>This is a text with a <a href="#">link 4</a> and <a href="#">another link 4</a></p>
</div>

To rotate the content of the div you might write code like this:

$elements = $('.rotating-content').find('p');
$elements.hide().first().show();

setInterval(function() {
   $elements.filter(':visible').fadeOut('slow', function() {
      $next = $(this).next();
      if ($next.length === 0) {
         $next = $elements.first(); 
      }
      $next.fadeIn('slow');
   });
}, 4000);

Putting everything into action results in the following demo:

Accessible Rotating Content

To solve this accessibility issue while achieving the same effect, we need to employ a different jQuery method, fadeTo(), and one of my favorite CSS helper classes ever, usually called visuallyhidden or visually-hidden. The code of this helper class is shown below:

.visually-hidden
{
   border: 0;
   clip: rect(0 0 0 0);
   height: 1px;
   margin: -1px;
   overflow: hidden;
   padding: 0;
   position: absolute;
   width: 1px;
}

Adding this class to any element will visually hide the element without setting its display property to none.

Now, instead of using the hide() method to hide the element or the show() method to show it, we’ll add or remove the visually-hidden class as needed. Besides, to recreate the nice animation we’ll use the fadeTo() method. The latter allows you to set the opacity you want the element to reach but when it has completed its task, it won’t update the display property (to learn more about this method you can refer to the official documentation). So, we’ll pass to it the value of 0 when we want to hide the element and 1 when we want to show it. Finally, we’ll also set the initial opacity value to 0 to all the elements we want to animate.

The resulting code is shown below:

$elements = $('.rotating-content').find('p');
$elements
   .not(':first-child')
   .addClass('visually-hidden')
   .css('opacity', 0);

setInterval(function() {
   $elements.filter(':not(.visually-hidden)').fadeTo('slow', 0, function() {
      $next = $(this).addClass('visually-hidden').next();
      if ($next.length === 0) {
         $next = $elements.first(); 
      }
      $next.removeClass('visually-hidden').fadeTo('slow', 1);
   });
}, 4000);

Putting everything into action results in the following demo:

With this simple change in the code we’ve created a more accessible widget to show rotating content. To see the difference between the two demos I invite you to use the TAB key to navigate the page.

Conclusion

In this article I’ve described an important accessibility issue that can be found in some code used to create a rotating content effect. Some of you may have unintentionally added it to a website built in a widget like the one discussed, but there is nothing to be ashamed of. Everyone ignores a lot of important notions before they learn about them. Yours truly discovered this important issue not so long ago (thanks to the work of people like Steve Faulkner and Léonie Watson).

While learning this simple trick may help you, the main take away lesson here is that when you develop any feature of a website, you should also verify that is accessible, otherwise you risk locking some of your users in an inferno of frustration and inaccessible content.

Sponsors

No Reader comments