Note that there are some explanatory texts on larger screens.

plurals
  1. POpreventDefault(), scrolling and accessibility
    text
    copied!<p>I'm adding a JavaScript-powered sub-window to a site. Basically, part of the UI is positioned off the left edge of the screen until the user triggers a link; then it's moved into a visible position. I have a series of five <a href="http://www.libsys.und.edu/dev/az/" rel="nofollow">test cases</a>, but haven't got the reputation points to link them individually yet.</p> <p>For accessibility purposes, I want to use a link containing a document fragment, thus:</p> <pre><code>&lt;a href="#quicklinks" id="quicklinks-trigger"&gt;Quick Links&lt;/a&gt; </code></pre> <p>With corresponding JavaScript (using jQuery):</p> <pre><code>$("#quicklinks-trigger").click(function(e){ $("#shadow").removeClass("default"); $("#shadow").addClass("active"); }); </code></pre> <p>The #quicklinks HREF redirects the internal cursor (aka caret) of screen readers to the beginning of the newly-revealed UI. There's a corresponding link in the Quick Links sub-window, which redirects the cursor back to the main part of the document (<code>&lt;a href="#main" id="close-quicklinks"&gt;&lt;/a&gt;</code>). You can see this in action with Test Case 1. If you listen to it with a screen reader (I'm testing with NVDA), the screen reader happily skips to the Quick Links when the link is triggered, and back to the main document when the Quick Links closing link is triggered.</p> <p>It also scrolls the page up and down in response to the document fragments, which is ugly and annoying. That can be suppressed using <code>window.preventDefault()</code> -- see Test Case 2, which works very smoothly and doesn't scroll around the document, thus:</p> <pre><code>$("#quicklinks-trigger").click(function(e){ $("#shadow").removeClass("default"); $("#shadow").addClass("active"); </code></pre> <p>e.preventDefault(); });</p> <p>Unfortunately, the call to preventDefault() also prevents the browser from moving the cursor to the right spot. A blind user can trigger the link there, and then the screen reader will proceed to the next item in source-code order, not the Quick Links UI. The easiest way to fix THAT would be to put the HTML defining the Quick Links sub-window immediately after the trigger link; but I can't do that, because the CMS that this is destined for is not playing nice with large blocks of HTML inserted into menus.</p> <p>I've tried some other approaches to eliminating the scrolling. Test Case 3 scrolls the window back manually:</p> <pre><code>$("#quicklinks-trigger").click(function(e){ $("#shadow").removeClass("default"); $("#shadow").addClass("active"); window.setTimeout(function(){ scrollTo(0,0); }, 1); }); </code></pre> <p>... which works but has a visibly jerky effect because it scrolls down and then back up, so that's no better than test case 1. </p> <p>In Test Case 4, I tried using preventDefault() in combination with focus() in the hopes of moving the internal cursor manually:</p> <pre><code>$("#quicklinks-trigger").click(function(e){ $("#shadow").removeClass("default"); $("#shadow").addClass("active"); $("#quicklinks").focus(); e.preventDefault(); }); </code></pre> <p>But it didn't work, because #quicklinks is a DIV, not a focusable element. I suppose I could add a hidden focusable element in the Quick Links HTML, but that would be kludgy.</p> <p>In Test Case 5 I tried removing the ID attribute from the targeted element, rewriting the fragment identifier with the onhashchange event, and then restoring the ID:</p> <pre><code>function cfl_hash(fragment){ // Get the section the fragment refers to. var target = $(fragment); // Save its current ID. var id = target.attr("id"); // Remove the ID so the browser won't scroll. target.attr("id",""); // Rewrite the hash to the desired fragment, only if onhashchange event supported. if("onhashchange" in window){ location.hash = fragment; } // Put the ID back in place. target.attr("id", id); } $("#quicklinks-trigger").click(function(e){ $("#shadow").removeClass("default"); $("#shadow").addClass("active"); cfl_hash("#quicklinks"); }); </code></pre> <p>Which had the unhappy effect of allowing the scrolling but preventing the cursor move. I think I have the sequence of events wrong in the ID swap; this ought to work for suppressing the scrolling, though I'm doubtful that it will allow the cursor move.</p> <p>It's really annoying that you can't cancel the scrolling for sighted users without also canceling the cursor redirect for screen reader users.</p> <p>So far I've only tested with Firefox and NVDA. I have no idea how this would play out in other combinations of browser and screen reader.</p> <p>Suggestions?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload