display:none, drop-down-menus and screen-readers - html

I have often read that using display:none for drop-down-menus (like done here) is bad practice, because it is inaccessible for screen-readers.
In this article: http://simplyaccessible.com/article/better-for-accessibility/ the author states that the position-off-left alternative from display:none has also downsides and suggests the following to make the drop-down-menu keyboard accessible:
Option 2: use display:none and have a :focus state to match :hover
that makes it display:block and brings the sub menu items onto the
page, allowing them to receive the focus, but only while they are on
the screen.
The :focus adjustment is realized with JavaScript. He gives an example on http://examples.simplyaccessible.com/css-menu/option-2.php.
Question 1:
Is the drop-down-menu from option 2 accessible for screen-readers? Do screen-reader read the complete page, and then you can tab through the page and they read out ever link? Would this means that the sub-menu is only read by the screen-reader when the person tabs through?
Question 2:
Using display:none has for me the great advantage that I can use jQuery functions like .slideDown() and .slideUp() which add a nice animation effect on the drop-down-menu. If I use position:absolute and hide the sub-menus off-left, how could I then get nice animation affects similar to .slideDown() and .slideUp()?

Answer 1: The simple answer is yes.
Longer answer:
Screen readers have a lot of options to move around a page, list out all of the available anchors, etc. NVDA, for example, also reads information via mouse interaction. Often, though, the focus of accessibility discussion is on keyboard users since they are often forgotten by developers. If a user is tabbing through the page, anchors that are visible (not display none) can have focus and be read. So the sub-menu is only accessible to the keyboard user (in option 2) when tabbing through the navigation. This applies to both visual and screen reader keyboard users. You can add your own keyboard interactions so content is available beyond tabs. However, keep in mind that the end user may not know how to use the menu. You'll also want to be mindful of keys already bound to screen readers.
Answer 2: Simple answer - you may want to consider CSS3 animations/transitions.
Explanation:
The slide aspect can be animated (if you have variable heights) using max-height and overflow hidden. So by default max-height of the sub-menu is 0 and then when the class is added you can set it to a number you think makes sense.
.menu li { position:relative; }
.sub-menu {
position:absolute;
top:100%;
left:0;
width:100%;
max-height:0;
opacity:0;
overflow:hidden;
transition:all 0.3s ease-in;
}
.active > .sub-menu { max-height:99em; opacity:1; }
If you make it 9999px the transition/animation look and feel will be influenced differently than 250px. Below is a simple CSS example of this:
Longer discussion point:
There wouldn't be much benefit for hiding the menu with position absolute off-left vs. display none for menus, if using an approach similar to the option you mentioned. You could get into a discussion on when JS is disabled and needing the content available then. Display none by default would prevent keyboard users from getting the content still (screen readers do understand Javascript, though). But the JS debate opens up further dilemmas, if we really want this to be perfect for all users without Javascript with different situations. With the content only visually hidden with the position absolute off left approach, a keyboard user who is a visual user will be able to focus on the anchors but won't ever see the content and may get lost (since it remains off screen).
So it isn't easy if we really want to account for all users in all situations. We have to set some restrictions sometimes and progressive enhancement is a possible aspect to keep in mind. Maybe the sub menus are only available to Javascript users. If interior pages have rail navigation of the sub section links then non-JS users regardless of screen reader user or visual keyboard user can still access all of the pages of the site.

Related

How to change values of tabindex and aria-hidden depending on browser size?

For desktop browser sizes I have a navbar across the top of the page, when browser reduces to mobile size it becomes a hamburger menu. As the menu is hidden at mobile size, then for accessibility reasons I believe that, the elements within the menu need to have attributes of tabindex=-1 and aria-hidden=true. The website is being built using HTML/Jinja2, CSS, client side JS and Python/Flask.
As you can see from the CodePen below I am able to toggle the aria-hidden attribute once the menu has been opened.
[My demonstration repsonsive menu using CodePen] (https://codepen.io/janlikescodepen/pen/wvJmdBZ)
Have a look at the window resize event -
https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event
As well as window.innerWidth -
https://developer.mozilla.org/en-US/docs/Web/API/window/innerWidth
The resize event listens for when the window size changes, and the innerWidth will tell you what size the window is so that you may conditionally modify the DOM depending on the window size.
Here is a simple example of what you may be looking to do -
window.addEventListener('resize', function() {
if (window.innerWidth > 800) {
console.log('Window is greater than 800px');
} else {
console.log('Window is less than or equal to 800px')
}
});
The best and simplest is in fact to entirely rely on CSS display property and nothing else.
An element which isn't displayed because of display:none isn't focusable, nor readable by a screen reader either. That's implicit. You don't need to worry about aria-hidden or tabindex in this case, which is much easier.
You may use CSS property visibility instead of display, if you wish, the effect is the same.
For anyone stuck on a similiar problem - wanting to creating a simple dropdown menu that does not disrupt the tabindex flow and screenreader flow, then my solution to this problem is using simple CSS + JS. The steps for it are:
At the mobile breakpoint the menu is hidden using display:none; and the hamburger is displayed
Clicking the hamburger calls a JS function that adds a CSS class to the menu that causes menu to be displayed because the class has display:flex and is lower down the stylesheet than the CSS style mentioned in step 1, therefore overriding it.
Clicking the hamburger calls the same JS function, but this time removes the class that was added in step 2, thus hiding the menu.
As suggested by QuentinC and Graham Ritchie, I used display:none instead of height:0 to hide the menu because this solves the issues for keyboard only or screenreader users.
[View demo code in Codepen.][1]
[Codepen]
Notes:
If you are thinking of using JS to toggle display:none/display:flex, then I warn you that you might face some specificity issues. This was my initial attempt, but I encountered specificity issues that I could only resolve by using !important. Simply adding and removing a class, as per my example, does not create specificity issues because there is no inline styling or html ID.
[1]: https://codepen.io/janlikescodepen/pen/yLMKxZB

Accessibility: wrapping list items in buttons for better keyboard navigation/accessibility

I frequently have use cases in my application where i need a list of items which need to be interactive, like clicking on an item should perform some action.
I usually wrap up the list item (li) content in a button, which kinda makes sense as the list item is interactive. This also helps with making the list items keyboard accessible with TAB. But, as much as i understand, this also poses a problem that a keyboard user would have to TAB through the whole list to get out off it. Would it be better instead to manage focus in the list using something like roving tabindex and allow ARROW keys for navigation within the list and TAB to focus in and out of the list ?
I am seeking validation for whether or not this is a good way to implement this kind of functionality, and pointers to any real world implementations
My real world experience is that you shouldn't put anything inside a button which is not related to a button semantic role. And strictly speaking, you shouldn't put list items inside anything that isn't a list.
Putting the buttons inside the list items would be better, but read on.
A list of items that 'perform some action' is (semantically) a menu, (or perhaps a toolbar which is much like a menu, but doesn't have the open/close feature expected of menus).
So you should get good results if you put role="menu" on the element containing the buttons, and role="menuitem" on the buttons.
Don't put the button that opens the menu (the "menu button") inside the menu. (I've wasted a lot of time on this).
There is no "menubutton" role. Just use an html <button> or something else with role="button". Then associate the menu button with the menu using aria-controls="yourMenuID". There are some other aria attributes you should use too, such as aria-expanded="true"/"false" (on both menu and menu button - and kept in sync with javaScript) and aria-haspopup="true" on the menu button.
If you take a little care, you can use CSS attribute selectors to style the menu according to the aria attributes. For example:
*[role='menu'][aria-expanded='false'] {
display:none;
}
*[role='menu'][aria-expanded='true'] {
display:block;
}
And yes, you should manage focus. Either with the roving tabindex technique or aria-activedescendant. I prefer the latter because it makes things more explicit but roving tabindex seems slightly more common. Both techniques are well-supported across a range of browser/AT combinations.
There are clear recommendations for how accessible menus should behave (with links to example code) here. Menu button and toolbar behavior is described further down in the same document. It's an excellent resource.
Good luck.

Hide Element but Preserve for Screen Readers (can't use display:none, visibility:hidden, or opacity:0)

I have an audio-element in my HTML whose only purpose is to make an announcement to blind users via a Screen Reader. It's a DIV, but it's invisible to regular users.
The way to announce something is by creating an element with role=alert (no other way to do it, there's no JS function to directly "speak" to a reader, for example):
<!-- This element can be dynamically added OR shown (via JS) to make a Screen Reader announcement -->
<div role="alert">This will be announced to Screen Readers.</div>
However, I can't have this "audio assistant" element be visible to regular users.
1) Can't use display: none; -> the Screen Reader won't pick it up
2) Can't use visibility: hidden; -> the Screen Reader won't pick it up
3) Can't use opacity: 0; -> because space is taken up, layout must be exactly the same
I found this solution:
https://stackoverflow.com/a/25339638/1005607
div {
position: absolute;
left: -999em;
}
This works great, it solves my problem. But it's a bit of a hack. I wanted to ask: Is there a better, more standard way to solve this problem?
It's a common practice to use CSS to visually hide an element but allow it to be discoverable by screen reader users. It's not necessarily considered a "hack".
There are more CSS properties needed than what you tried. See What is sr-only in Bootstrap 3? for details.
Also, you can search for the "visually-hidden" class.
Both sr-only and visually-hidden are common names used to name the class that visually hides elements.
Also, your understanding of role="alert" isn't quite accurate.
The way to announce something is by creating an element with role=alert (no other way to do it, there's no JS function to directly "speak" to a reader, for example):
role="alert" has an implicit aria-live="assertive". Elements with aria-live will announce changes to that element to screen readers. It will not automatically announce that element. For example,
<div id="foo" aria-live="polite"></div>
<button onclick="document.getElementById("foo").innerHTML = 'hello'">update</button>
When I click on the button, text will be injected into the <div> and the new text will be announced.
In general, you want to use aria-live="polite" and not aria-live="assertive". When you use role="alert", you get aria-live="assertive".
So if your page is updating its contents, then using aria-live is the right thing to do. But it does not cause something to be announced just because your page loaded.
The screen reader user has many ways to navigate a website using quick navigation keys defined in the screen reader (such as H to go to the next heading [h1, h2, h3, etc], or T to go to the next table, or L to go to the next list, etc.), provided your HTML is using semantic elements (such as <h1>, <table>, <ul>, etc). If you have text that is hidden to sighted users, then that text can be found by screen reader users without you forcing it to be read automatically.
I'm not sure if this is a "better" way, but this will hide it in place.
div {
overflow:hidden;
height:0;
width:0;
}

Hiding content from screen-readers - and related questions

Intro:
I'm coding a single-page app. It's a sort of e-book reader and I want to optimize screen reader experience.
For general performance reasons (load times, HTTP requests) all of the functional components of the app are always present in the DOM, visibility managed by CSS. Only the actual content is dynamically loaded.
That means there's a lot of stuff present that is not needed all the time, e.g. the login/register pages.Sighted users won't know, but screen reader users could be annoyed.
There's also things that I figure shouldn't matter to screen reader users, like a bunch of visual options (font size, colors...).
What I intend:
I want to hide certain sections by applying aria-hidden="true".
I want to dynamically apply that to elements which are not currently functional, like the register page for a logged in user.
Also, I want to generally hide certain "presentational" sections, like visual options.
Questions:
Is that good practice?
Are there drawbacks?
Is it necessary?
Are there other/better ways of telling sr users that elements are of no use to them?
and, last no least,
Are there good ways of directing the attention of sr users to certain elements?
-
p.s. I have already structured the DOM sensibly, like
<body>
<main role="main"></main>
<nav role="navigation">
<button>Next Page</button>
<button>Previous Page</button>
...
</nav>
<menu role="menu">
<ul>
<li><button role="menuitem">Important Task</button></li>
...
<li><button role="menuitem">Least Worthy Task</button></li>
</ul>
</menu>
<div class="options">
...
</div>
to make sure that the controls should be tab-focused in descending order of use frequency.
I assume that the act of changing page would remove/hide the current content and unhide the new page? In which case it sounds like you are taking a good approach from a showing/hiding point of view.
I did a quick gist / cheat sheet recently of current best practice for: hidden from all, hidden from screen readers, or shown only to screen readers:
https://gist.github.com/alastc/7706437
For items which are currently not active but disabled, it might be inconsistent (and therefore confusing) to hide them? Perhaps use the disabled/aria-disabled attribute instead.
As the content and next/previous are first in the order, having several disabled controls after those should be fine. NB: When reading screenreaders have a 'browse' order that follows the DOM and is not affected by tabindex. You're order looks good, so don't try and over-ride it with tabindex.
Also, please pay attention to keyboard focus. I.e. when you select 'next', does the keyboard focus move to the top of the next page? I wrote an answer about the keyboard focus aspect for single-page apps.
Also, as you have multiple nav elements it would be helpful to label them, then they could be announced as "Page, navigation" and "Options, menu" (for example).
Take a look at the following link. It lists ways to hide content from screen reader users as well as what combinations of screen reader and browsers behave properly.
http://www.html5accessibility.com/tests/hidden2013.html
Your approach will work however you are over thinking things.
Any content hidden in CSS with display: none or visibility: hidden is also hidden to screen readers

CSS dropdowns on touch-based clients. Are pure CSS dropdowns going to become extinct?

My company is starting to move toward adding the iPad as a browser i have to test my work on. This got me thinking...
Since touch-based clients don't have a :hover state are pure CSS dropdowns going to go away?
Then i thought even if you add some javascript to make the menus popup on click... What happens when the menu item (that expands to another menu) is also a link. How do you tell the difference between a click to see the menu or a click to go to that link?
What's going to happen with dropdown menus when touch based clients become more ubiquitous? Are there any workarounds out there yet?
Pure CSS dropdowns are possible on touch devices thanks to the :target pseudo-class. Basically, the pseudo-class is active for objects that have an id matching the current URL fragment. This means that the URI fragment can be used to store and share state with CSS. For example, let's say we're on http://example.com/, which has the following HTML and CSS:
<style>
#menu {
display: none;
}
#menu:target {
display: block;
}
</style>
Show the Menu!
<div id="menu"> ... </div>
The menu is hidden by default. Clicking or tapping the link will change the URL fragment to "menu" (full URI: http://example.com/#menu). Because now there is an element with an id equal to the URI fragment ("menu"), the :target pseudo-class applies, and the display property is changed.
Further reading:
Usage and Example at Mozilla Developers Network
Implementation of a touch-friendly pure CSS dropdown
This is kind of a design issue forced by a technical issue. I'd probably redesign/reorganize my content into one of three ways:
1- Click-activated mega-menus (example). The downfall here is that you might have real estate issues.
2- Top-Level Category links that lead to Navigation Pages. The downfall here is that it requires an extra page load to get to the content.
3- Make each Menu Item consist of two buttons, one to navigate to the page (the text) and one to expand the child menu (an arrow.) You'd still need, though, to provide the child navigation, if present, on the page the user goes to when they click a menu item.
my nav bar has this functionality (collins.class401.com/nav) for the crap you need
its a modified version of TJK_DropDownMenu http://www.tjkdesign.com/articles/keyboard_friendly_dropdown_menu/default.asp
their version (and mine) uses visibility for :hover
their version also only supports having <a>'s as menu items, while mine also supports <span>s (though using spans breaks their keyboard navigation) if you want something like a form, or a button in your menu, like i have
their version usually works for :hover on ipod touch, as long as you click in the 'white space'
my version is much more friendly to touch devices, and has the clickable arrows to toggle the display using prototype.js,
or, if they can't hover, and javascript is off, setting a php session and reloading the page, then inserting a style to the style tag at the end of the page which will overwrite the visibility and display according to whether the clicked to show or hide