Does using absolute positioning on a website negatively affect voice activation software?
Context:
I'm working for a company who have had their website's accessibility assessed. One of the comments was:
The tick box shown here is not being picked up by Dragon.
This means that a voice activation user would need to use keyboard commands in order to tab onto them.
Ensure that voice activation users are able to access the checkboxes by implementing the following in the CSS:
.checkbox__input {
/* position: absolute; */
cursor: pointer;
/* left: 0; */
/* top: 0; */
width: 38px;
height: 38px;
margin: 0;
opacity: 0;
}
The commended-out properties are their suggestions on what we should remove from our CSS.
I am aware that using position: absolute takes content out of the normal flow of the page. However, we are wrapping each checkbox in a container that is relatively positioned.
Their comment is suggesting to me that there is an issue around using voice commands on content that is absolutely positioned, but I can't seem to find anything online about if there actually are any issues.
For those curious, we do not want to implement their proposed changes because it changes our page design negatively.
The OP is asking about speech recognition, such as Dragon, and not screen readers.
Positioning has nothing to do with speech recognition and the recommended CSS seems silly to me. Two obvious things can affect speech recognition:
the role of the element
the displayed label of an element compared to the underlying accessible name
For the role, if you had a <div> that was styled to look like a checkbox, but the <div> did not have a role="checkbox", then a speech recognition user would not be able to say "click checkbox".
For the label, if the visual label of the checkbox does not match the accessible name of the checkbox (which should be a rarity), then a speech recognition user might not be able to (directly) select the checkbox. For example:
<input type="checkbox" id="mycheck">
<label for="mycheck">do you like dogs?</label>
A speech recognition user will be able to say "click dogs" or "click like" or "click <any word that is part of the visible label>".
However, if you had something like:
<input type="checkbox" id="mycheck" aria-label="are you a puppy lover?">do you like dogs?
then visually, both cases would look the same but the visible label, "do you like dogs?" does not match the accessible name, "are you a puppy lover?", and a speech recognition user would not be able to say "click dogs" or "click like" because neither of those words are in the accessible name. They'd have to say "click puppy" or "click lover", which would not be obvious.
Now, regarding positioning, if you had an object that was "on top" of the checkbox and that object on top received click events, then maybe positioning might affect Dragon, but I'm not sure. With a mouse user, if they try to click the checkbox but something (whether visually apparent or not) is on top, that top object will receive the event. If the speech recognition user says "click <checkbox name>" and an object is on top of it, I don't know if the checkbox will receive the event. It seems like the checkbox would get selected because you used the name of the checkbox and didn't rely on the DOM order for an object to receive the event.
Screen readers typically follow the order of the HTML (including any HTML generated by scripts) when reading a document. When CSS is used to position content, the content that appears on the screen can appear be in a different order from what appears in the code.
From Penn State's Accessibility Office:
The position attribute is used to change the visual position of an element regardless of where it is in the code. For example any item with position:absolute and position set to top:0px and left:0px will be displayed first visually, even if the div is the final text in the HTML code. Alternatively, an item may be listed first in the code, but actually be positioned to the bottom right side of the page visually.
This can be a problem for screen reader accessibility because content can be read out of context and therefore be confusing.
http://accessibility.psu.edu/css/readorderhtml/#fxd
Relative positiong presents the same problem.
The only way to overcome this issue is to allow items to render on screen in the order that they appear in the HTML. This may mean making adjustments to your HTML code, scripts, templates, etc.
This doesn't mean that you can't use CSS to position and align things -- you certainly can. It just means that you shouldn't use CSS to re-arrange the order of things.
Related
WCAG states that an element that has focus should always be visible to the user. This is especially hard, if not impossible in a chat window where space is limited.
When a keyboard or screen reader user tabs to the first button option and selects it, the content scrolls and button is no longer visible, breaking the "focus always visible" WCAG rule. Also if there is more than one button in the list the focus stays on the button and if they continue to tab, the window will scroll to where the focus is set. This is disorienting, and one can argue that when selecting a button the other options are not relevant, since new options are now available.
Example: https://recordit.co/2jDDvqg98J
One option is to stop scrolling when reaching the button so that the button is visible. But I feel that this is not a good experience and a compromise to comply with the WCAG rule. I have done some research and all conversational UI, with no exception, scroll to the bottom when new content is printed in the chat. If I deviate in the manner above to keep within WCAG I am breaking Jakobs Law.
Another option is to remove the focus from the selected button to the input field or the firs button in the next/new list of available buttons. But I feel that this will for blind users removes all points of reference.
Are there any other options or designs that you can think of to solve this in an accessible way?
Your example is someway too complicated.
Let's take a standard HTML page : if you focus an element with the keyboard, you are still able to scroll the page using the mouse (without modifying the keyboard cursor), and make the element disapear from the viewport. This does not invalidate any WCAG criteria.
Pressing a char key on a textarea will make it visually focused again. For a button or a link, that would require tab then shifttab, to make the button visible and focused again.
Visual focus and keyboard focus are two distinct things, but if keyboard focus impacts the visual focus, that does not reciprocate
The problem you might have is not a problem with the focus, but more a problem with Time limits.
Don't scroll if the user is not at the bottom of the window,
Don't scroll if an action has been performed during last N seconds, or wait P seconds if no other action is performed before scrolling.
Indicate that new messages have been received if the windows if not scrolling.
I think that Slack has a good implementation of the "do not scroll and indicate new messages" if you are not at the bottom.
Not a full answer
This is too large a question to answer in full, there are hundreds of things to consider and with just a GIF to see the behaviour I can only generalise.
Focus off screen
You have taken WCAG to the absolute letter and a little too far. The intention of this point is that when I change focus the focused item is visible on the screen.
If I scroll a web page you cannot expect focused items to stay on the page (otherwise no page in the world would be compliant if it was longer than a screen length!).
As long as when I focus the next item it scrolls into view and has a focus indicator I can see (correct contrast, not colour dependent) you are WCAG AAA rated on this point!
Auto scrolling content
This is where things get 'murky'. In your example content is added to a chat box and so the currently focused item scrolls off the screen.
Now if we move the focus to the latest options (buttons that appear) we have a problem that it may interrupt the flow of the screen reader and so they don't hear all the previous information and have to go back and listen again.
If we don't move the focus you have the problem you described where I press Tab (for example) and the page jumps back up before the content I just listened to.
Assuming we didn't have any other options this would still be preferable (not managing focus), but we do have options.
Time for some workarounds.
This is where accessibility gets fun, we need to find a few workarounds as there is no established pattern here.
I would argue that the biggest problem here is once the new text is spoken we jump back to the top of the page when we press Tab or other focus shortcuts.
One workaround for this would be to create a special div that gets focused the second i choose an option.
This div would have tabindex="-1" so it is not accessible via keyboard (only programatically).
The second I select an option we focus this div and then start inserting text.
That way when I press the <kbd>Tab</kbd> or shortcut for the next button it jumps to the first new option.
I have created a rudimentary fiddle below, it would need some improvement but gives you a pattern to test against / work with. (go full screen or you may not see the added buttons etc.)
var hasLoadedMore = 0;
$('.loadMore').on('click', function(e){
if(hasLoadedMore == 0){ //just a horrible hack to simluate content only loading once when you click an option.
console.log("option chosen");
$('#focusAdjuster').attr('aria-hidden', false);
$('#focusAdjuster').focus();
console.log("focus adjusted");
loadContent();
}
});
function loadContent(){
///ugly way of simulating the content being added dynamically.
$('#chat').append('<p>additional text</p>');
$('#chat').append('<p>more text</p>');
setTimeout(function(){
$('#chat').append('<p>more text</p>');
$('#chat').append('<button>Option 1 new</button>');
$('#chat').append('<button>Option 2 new</button>');
}, 500);
hasLoadedMore = 1;
}
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap; /* added line */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chat">
<p>initial text</p>
<button class="loadMore">Option 1</button>
<button class="loadMore">Option 2</button>
<button class="loadMore">Option 3</button>
<div tabindex="-1" aria-hidden="true" id="focusAdjuster" class="visually-hidden">loading</div>
</div>
Explanation of fiddle
So they key points are the visually-hidden <div> and the accompanying line in the JavaScript that focuses that div before loading more content.
The div lets us change the focus after clicking a button. I also added 'loading' to the text inside that div to add an additional purpose as your application will be AJAX powered.
The div has tabindex="-1" so it cannot receive focus. I also added aria-hidden="true" to this and toggle this off when an option button is clicked, just before giving it focus.
I would toggle this back when focus leaves this div in the real world but I wasn't doing that in a quick demo fiddle.
Doesn't this 'fail' WCAG?
Yup! In this example I made a non-focusable item focusable and it has no action. I still think this is preferable to making it a <button> as that implies it has an action. It obviously isn't perfect.
However the key part of WCAG is the 'G' - they are Guidelines. The way I am suggesting is a 'hack' or a compromise based on the fact that I am realistic about development time and tech limitations.
The 'proper' way you can do the above without the div is with some careful focus management. With unlimited time and budget I would definitely do that.
But given that you don't have to only think about the Tab key with screen readers (you can navigate by links, buttons, headings, sections etc.) that becomes a nightmare when trying to intercept key strokes and so the above is the simplest way I could think to do this.
Alternative pattern.
Because the previous example 'fails' WCAG there is another option, however I would argue this is worse and introduces lots of problems.
Replace the text within the div with new text each time.
The down side is that you would need to provide 'previous item' buttons each time and track them, the plus side is this would be WCAG compliant (although I would argue not as usable even though you 'pass' the criteria.)
Also providing those 'previous' buttons introduces a number of problems with focus management again (when do we make them visible, do they get the focus, do they add more confusion?).
Think of it like a form wizard pattern, each set of questions is a 'step', so you can go back to previous steps, and you can only see the current step on screen.
I included this as this pattern could be expanded with some thought and to give the OP / other people some ideas, do NOT use it as it is
var hasLoadedMore = 0;
var optionChosen = "";
$('.loadMore').on('click', function(e){
if(hasLoadedMore == 0){ //just a horrible hack to simluate content only loading once when you click an option.
optionChosen = $(this).text();
console.log("option chosen", optionChosen);
loadContent();
}
});
function loadContent(){
$('#chat').html('<button class="previousQuestion">You chose ' + optionChosen + '<span class="visually-hidden">(click here to go back and chose a different option)</span></button>');
$('#chat').append('<h3>' + optionChosen + '</h3>');
///ugly way of simulating the content being added dynamically.
$('#chat').append('<p>additional text</p>');
$('#chat').append('<p>more text</p>');
setTimeout(function(){
$('#chat').append('<p>more text</p>');
$('#chat').append('<button>Option 1 new</button>');
$('#chat').append('<button>Option 2 new</button>');
}, 500);
hasLoadedMore = 1;
$('.previousQuestion').on('click', function(){
console.log("now you would restore the previous question");
});
}
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap; /* added line */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chat">
<p>initial text</p>
<button class="loadMore">Option 1</button>
<button class="loadMore">Option 2</button>
<button class="loadMore">Option 3</button>
<div tabindex="-1" aria-hidden="true" id="focusAdjuster" class="visually-hidden">loading</div>
</div>
If I have a 3 buttons on a page, and choosing one causes them to be hidden, and then show another div containing some form elements, I want to correctly notify the new content added shown. My understanding is dynamic content changes such as showing a region need to be handled properly in terms of WCAG. Is there a standard way to handle this in terms of aria/html?
I've tried aria-live, since it's often suggested for this scenario, on the outer div of the new region, but even with aria-live="polite" I get undesirable side affects. Let's say the region shown contains a small form. When focus moves to a text field, and I begin typing, I got the odd behavior that JAWS will repeatedly start reading the label again and again for each single keystroke as the user types characters in the input. If I remove the aria-live attribute on the parent div, then tab through the form the label is only read once on field focus, and is not read again as the user is typing.
I.e. it seems the parent having an aria-live is causing child elements like labels to get read more aggressively, even though the region being shown is a one time change, and there's no dynamic changes after that point.
This odd behavior seems to imply that aria-live is better suited for small isolated elements such as errors/alerts being added to the page, rather than large regions.
Should I be using a role instead?
<form role="form" action="/submit" method="post">
<div hidden id="section1" aria-live="polite">
<h2>Form Header</h2>
<div>
<label for="RequestNumber">Request Number*</label>
<input id="RequestNumber" name="RequestNumber" type="text" />
</div>
</div>
</form>
The golden rule - don't use ARIA unless all other options have been exhausted.
What you actually want to do here is simply manage focus.
When you click one of the 3 buttons I assume a different form is shown. 99% of Screen Readers can handle this no problem (and for the ones that can't they are used with no JavaScript so make sure your website works without it if possible.)
When you click the buttons, hide them (if you have an animation then use aria-hidden, otherwise just display:none will do) and then when the new form is shown simply focus the form using JavaScript.
The screen reader will take care of the rest.
It may be advisable to add some visually hidden text on the buttons to inform the user that the buttons disappear and a form appears - just make sure you provide a way for them to go back to the buttons in case they made the wrong choice.
Visually Hidden Class For Reference
Use the below CSS to hide an inline span within the button if you feel it is appropriate information a screen reader may need.
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap; /* added line */
}
This sounds like a case of simple progressive disclosure. What JAWS is doing is not a bug, but exactly how aria-live works. Aria-live creates a sensitive region of the DOM that triggers an utterance by Assistive Tech whenever that region is changed. This is why wrapping a form in aria-live would be unwise.
If this is truly a progressive disclosure situation where the form is building itself ahead of the user based on their selections, aria-live notifications are not necessary. As long as the user's focus moves logically through the form elements as they are pertaining to their current task and content behind the user isn't changing, no alerts should be necessary.
In your example, you're wrapping the form fields and labels as well. You might want to just add the H2 into an aria-live region which will restrict the announcment to just that element.
(Apologies if I misunderstand the situation, but if selecting one of the buttons causes the button set to disappear and a div to be added, then the real question is where does focus land?)
I have a div element (which has another div inside it) which currently has role="button".
This element is under the body, and this creates a violation when
auditing with certain accessibility assessment tools (DAP specifically).
The reason for the violation: "All content must reside within a WAI-ARIA landmark or labelled region role"
When using roles other than "button" it becomes unclickable when using the JAWS screen-reader.
I've tried giving a role="complementary" the main div, and role="button" to its child div - this made the entire element unclickable using the keyboard.
Any suggestion will be most appreciated..
Thanks!
The div where you are using the role as complimentary should have a tabindex of -1. The button you want to focus to should have a tabindex of 0/1. This will make sure that the accessibility readers will focus on this component and when they do, it will select the button.
Here is a link that may help:
https://www.w3.org/TR/wai-aria-practices/
Hope this helps!
I'm creating a context menu for certain elements using a PopupPanel; the menu itself is going to be fairly large and complex. What I'm looking to do is to have a list of buttons, plus an image and some text, related to the element clicked.
My problem is that I'd like the buttons to always display directly under the clicked element, because that's convenient for the user; the issue is that when PopupPanel is near the edges of the screen, it automatically changes position to be fully visible, not aligning its left side to the element as usual. I like this behavior, but it moves the position of the buttons away.
So what I'd like to happen is: normally the buttons are on the left of the panel, the other stuff is to the right. When the panel is close to the right of the screen, I'd like the buttons to instead be on the right (and thus under the clicked element) and the other stuff on the left.
Is there a clever way to do this, either in GWT or better yet, using only CSS? PopupPanel itself doesn't seem to tell you when it's going to get flipped, sadly. The only solution I currently have is to manually check the position and width of the popup before showing it and adjust accordingly, but I'm hoping there's a better solution.
Here is what I suggest (based on my own implementation of a similar use case):
Have the position callback implementation accept references (in constructor) on:
PopupPanel element
element on which user right cliked
the content you put in the PopupPanel
Replicate (I know this not DRY but implementation is package private) the code from default position callback
When opening to the right invoke a method that changes the layout of your content (CSS based or otherwise)
I hope it helps. If you find something better let me know.
I'm having a problem with FIREFOX. I have an invisible list control over a drop-down control (html 'select'). Don't mind why, but I will say that the over-layer is a pop-up that appears as part of another custom control.
Even though it's hidden, it's preventing me from clicking on the underlying drop-down control, making the underlying control seem disabled. It's not disabled though, because I can tab over to it. I just can't click on it. I know it's the overlay causing the problem, because I moved the underlying control off to the side and it works again.
Is this a bug in Firefox? This isn't like setting a translucency value; it's disabling rendering of the control altogether, so I don't think such an invisible control should be intercepting mouse events.
This behavior does not occur in Internet Explorer.
Perhaps there is some other CSS property I can set in JavaScript to toggle its mouse event capturing ability along with its visibility.
dd = document.getElementById('lstStudents');
if (dd.style.visibility == 'hidden') dd.style.visibility = 'visible'; else dd.style.visibility = 'hidden';
Update: I just read a description for the CSS visibility value "hidden" that read "The element is invisible (but still takes up space)". So I guess I'll have to set it's height to zero along with setting it's visibility to solve this problem.
change your over-layer control's z-index to, say, -1. style="z-index: -1;" This will place it underneath everything, allowing direct access to drop-down. You might have to dynamically change the z-index to bring over-layer back on top when visible.
More info
How are you hiding the element? If I remember it right, "visibility: hidden" is supposed to (rightly) work the way you describe, while "display: none" will banish rendering altogether.
If that's not the cause, can you confirm using Web Developer Toolbar that it is indeed the invisible control that is causing the problem and not another that has opacity set to 0 or something?
The way I've done popup boxes before in Firefox was with CSS properties.
z-index: 500;
display: block;
to show an element, and
z-index: -10;
display: none;
to hide it.
Now. My values for z-index are extreme, but that's just what I chose. This works for me, but my app targeted Firefox specifically; aaaaand I'm using the display property, which you stated you want to avoid.
If you're concerned about using display:block or display:hidden, I think maybe you could try to play with positioning, or sizing the element.
Either make the popup element absolutely positioned and move it offscreen when invisible, or maybe try to make it 0px width and 0px height when invisible. That's two things I would potentially explore if I still had problems. I'm not sure if I would recommend these as best solutions though.
Really consider how many instances of your popup elements will have different display values, I found in my case to be using only two types, 'none', and 'block'. Maybe manipulating the display property will be enough for you.
Hope this helps.