1

Context

I am building a website with a marquee, <ul role='marquee'>...</ul> with content that visually changes every few seconds. The marquee sits at the top of the page above a form. The marquee displays helpful hints and promotional messages as the user is filling out the form.

The content displayed in the marquee does not change according to any user interaction, rather the marquee cycles through a static list of li tags.

Although the marquee may contain important information about the form, that information will be conveyed in appropriate places throughout the form.

Lastly, the marquee will never contain a link or other interactive element.

Task

In order to comply with WCAG, I am looking for the best practice as far as using ARIA attributes on the marquee.

Labeling

My initial thought is to add aria-label to help screen reader users know what the ul is all about. I have only seen this applied to button and a tags. Will it work the same on a ul tag? Or should I create a visually hidden h_ tag above and use aria-labelledby, like in this answer.

Next, I am unsure about what label to give. I came up with 'hints', 'tips', and 'advice'.

Then I thought about making those sound friendlier, for instance 'helpful hints', 'tips and tricks', and 'words of advice'. Is this overly casual?

My concern with all of these labels is that they may be too vague and non-descriptive.

What are your thoughts?

Hiding

Do you think I should simply apply aria-hidden to make screen readers ignore the marquee altogether?

My thinking behind this is that the information displayed in the marquee is disorganized (many messages without a consistent theme), and the messages that are important will be repeated elsewhere. I wonder if the marquee would only get in the way.

Other approaches

Please let me know if you have other approaches that maybe I have not thought of.

Minimal working example

const list = document.querySelector('ul');
const listItems = document.querySelectorAll('li');

let position = 0;
let animationID = null;

const startAnimation = () => {
  animationID = window.setInterval(() => {
    position = (position + 1) % listItems.length;
    listItems.forEach((item, index) => {
      if (position === index) {
        item.classList.remove('invisible');
        item.classList.add('visible');
      } else {
        item.classList.remove('visible');
        item.classList.add('invisible');
      }
    });
  }, 4000);
};

const stopAnimation = () => {
  window.clearInterval(animationID);
  animationID = null;
};

const initialize = () => {
  listItems.forEach((item, index) => {
    if (position === index) {
      item.classList.remove('invisible');
      item.classList.add('visible');
    } else {
      item.classList.remove('visible');
      item.classList.add('invisible');
    }
  });
  startAnimation();
};

window.onload = initialize;
list.addEventListener('mouseenter', stopAnimation);
list.addEventListener('mouseleave', startAnimation);
ul {
  font-family: monospace;
  list-style: none;
  margin: 0 auto;
  padding: 0;
  width: 100%;
  max-width: 360px;
  height: 36px;
  border: 1px solid black;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
}

@media (max-width: 400px) {
  ul {
    height: 56px;
  }
}

li {
  position: absolute;
  width: 100%;
  height: 100%;
  transition: opacity 500ms;
  opacity: 0;
  transform-origin: 50% 50% -30px;
  display: inline-flex;
  justify-content: center;
  align-items: center;
}

li.visible {
  animation: swoop-in 500ms linear forwards;
  opacity: 1;
}

li.invisible {
  animation: swoop-out 500ms linear forwards;
  opacity: 0;
}

@keyframes swoop-in {
  0% {
    transform: rotateX(-0.25turn);
  }
  100% {
    transform: none;
  }
}

@keyframes swoop-out {
  0% {
    transform: none;
  }
  100% {
    transform: rotateX(0.25turn);
  }
}
<ul role='marquee'>
  <li>All websites should be accessible</li>
  <li>Save money by signing up today</li>
  <li>This form will only take a few minutes</li>
  <li>Ask us about our discounts</li>
  <li>We will never share your information</li>
</ul>
Mathilda
  • 437
  • 3
  • 11

2 Answers2

2

There's no reason to add any ARIA attributes to this at all. Your end structure is a simple <ul> with <li> children, and assistive technology generally doesn't care about animation. Therefore, it will be treated by assistive technology like any other <ul> element.

Rule #1: Don’t use ARIA, use native HTML instead

https://www.deque.com/blog/top-5-rules-of-aria/

I'd also recommend removing role="marquee" from your markup, as this establishes an aria-live region, and that's probably not what you want, if you're not dynamically adding and removing list items.

It's not typically a good idea to try to override the text in a non-interactive element using things like aria-label, aria-labelledby, or aria-describedby for the reason that the accessible name specification is poorly defined (when it comes to non-interactive elements), and so the browser manufacturers all do their own interpretation which isn't consistent.

It's good to see that you have a method in place for pausing the animation, which puts you in compliance with S.C. 2.2.2. I don't think you need to do anything else here, but I'd always recommend testing with one or more screen readers for good measure.

Josh
  • 3,872
  • 1
  • 12
  • 13
  • Thank you for the advice! The link you sent: [role="marquee"](https://www.w3.org/TR/wai-aria-1.2/#marquee) explains "Elements with the role `marquee` have an implicit `aria-live` value of `off`". Do you still recommend removing `role="marquee"`? – Mathilda Jul 30 '21 at 21:42
  • 1
    Yes -- Based on your description that these are static elements and won't be updated, I'd recommend removing the role. – Josh Aug 02 '21 at 14:25
2

@josh had some good advice but a few things were not quite accurate.

I'd also recommend removing role="marquee" from your markup, as this establishes an aria-live region

While role="marquee" does make a live region, the default implicit value of aria-live is "off", at least according to the spec. I didn't test to it confirm that. But if the implicit value is "off", then it's not really a live region so I'm not sure why they call a marquee a live region.

the accessible name specification is poorly defined

The spec for the accessible name is very specific and well defined. You can see the order of precedence defined in "Accessible Name and Description Computation 1.1". All browsers must use this spec otherwise they're not a compliant browser. Firefox, Chrome, Safari, and Edge all follow these specs so you should be ok with accessible names.

However, that being said, if you specify the accessible name with aria-label or aria-labelledby, it might not be honored if the element you put it on doesn't have a role. See "2.10 Practical Support: aria-label, aria-labelledby and aria-describedby", specifically the third last bullet point.

  • Don't use aria-label or aria-labelledby on a span or div unless its given a role. When aria-label or aria-labelledby are on interactive roles (such as a link or button) or an img role, they override the contents of the div or span. Other roles besides Landmarks (discussed above) are ignored.

Also, the fourth last bullet point talked about list elements, which is your scenario:

  • Don't use aria-label or aria-labelledby on any other non-interactive content such as p, legend, li, or ul, because it is ignored.

I can visualize the concept you're planning, and as @josh said, if you have a way to pause the updates, then WCAG 2.2.2 is covered. Whether those updates are announced to screen reader users might be a personal preference. Some users might want to hear them and others might not. They might be a distraction if new text is read every 5 seconds (or however long you update it) so having a pause option helps screen reader users.

slugolicious
  • 15,824
  • 2
  • 29
  • 43
  • Can you please explain why there's so much variation in the accessible name computation between various screen readers as referenced in your "2.10" link? It seems that NVDA, JAWS, Voiceover, and Talkback are all doing things differently. It's possible that the browsers aren't the problem as I had initially stated, but that's a lot of variation for a spec that's supposedly well-defined. – Josh Aug 02 '21 at 14:19
  • 1
    FYI -- an `aria-live` region with a value of `off` is still a live region. It just doesn't pull focus. However, if the user directs focus to the live region, and updates are made via scripting, then it behaves like any other live region. – Josh Aug 02 '21 at 14:23
  • 1
    Good point on `aria-live="off"`. You are correct and I never noticed that nuance before. Most ARIA attributes that have an "*off*" or "*false*" value behave essentially the same as **not** having the attribute at all. But `aria-live` is different. If the user's focus is on the "off" region, then changes **will** be announced. If the user's focus is somewhere else on the page, then changes will **not** be announced. Pretty cool. – slugolicious Aug 02 '21 at 18:35
  • As far as the accessible name, do you have examples of differences? The browsers generate the name and surface it via the API or accessibility tree and that's what the screen readers announce. The screen reader itself has no role it generating the accessible name. Now, a screen reader might ignore something on the accessibility tree, but that's typically a bug in the screen reader. But I rarely come across those. – slugolicious Aug 02 '21 at 18:36
  • What I'm referencing is the link that I posted in my answer: https://www.davidmacd.com/blog/does-aria-label-override-static-text.html Everything works as expected on interactive elements (like buttons) or elements with explicit/implicit roles, but when you add `aria-label` or `aria-labelledby` to static elements like a `` or a `
      ` element, then the behavior seen is different in JAWS as compared to NVDA or Voiceover. More here: https://www.tpgi.com/short-note-on-aria-label-aria-labelledby-and-aria-describedby/
    – Josh Aug 02 '21 at 21:44
  • It's important to keep in mind what an "*accessible name*" is. The official definition on w3.org is https://www.w3.org/TR/accname-1.1/#dfn-accessible-name and says "*The accessible name is the name of a **user interface element***". So, as you said, "*Everything works as expected on interactive elements*". Perfect, the spec is working as defined. If you stray into non-interactive elements, the accessible name doesn't apply and you'll get unexpected results. See https://www.w3.org/TR/using-aria/#label-support. Now, you can often get an accessible name for non-interactive elements, but test. – slugolicious Aug 03 '21 at 14:50
  • The term "user interface element" is never explicitly defined, which is why I said that the spec is poorly defined and why it works differently in JAWs/NVDA/VO. What counts as a "user interface" and what doesn't makes a huge difference in the real-world output. Given that the original question was about overriding text on a non-interactive `
      ` element, I stand by my answer.
    – Josh Aug 03 '21 at 19:48
  • Also, I wouldn't recommend adding an aria role to a `
      ` element. It seems that the only roles that will get you a good level of support among assistive technology would be `navigation`, `search`, and `main`, which all seem inappropriate for this use case.
    – Josh Aug 03 '21 at 19:52
  • Yeah, there’s no point in using a `
      ` if you’re going to change the default role.
    – slugolicious Aug 04 '21 at 05:38
  • "user interface component" is defined all over the place in the WCAG spec. The actual definition is https://www.w3.org/TR/WCAG21/#dfn-user-interface-components and it's linked to from several success criteria (1.4.3, 1.4.11, 2.1.4, 2.5.3, 2.5.4, 3.2.1, 3.2.2, 4.1.2, as well as several AAA success criteria). – slugolicious Aug 24 '21 at 14:38
  • But your answer had good info, like I said. There was no need to restate the good stuff. But I wanted to point out a few clarifications. I think doing that is essential when it comes to accessibility and is absolutely “cool”. If sharing correct info is rude, then all of stackoverflow is rude. I never stated any opinions. I always pointed to reference urls. – slugolicious Aug 24 '21 at 23:48
  • I've tried the comment section before but if you have a lot of info to share you have to use the answer area. Whether we agree is too bad but I hope you continue accessibility work. – slugolicious Aug 26 '21 at 01:06