PreventDefault()、滚动和可访问性

发布于 2024-10-01 08:41:53 字数 2747 浏览 4 评论 0原文

我正在向网站添加一个由 JavaScript 驱动的子窗口。基本上,UI 的一部分位于屏幕左边缘之外,直到用户触发链接为止;然后它被移动到可见的位置。我有一系列五个 测试用例,但还没有获得声誉点还可以将它们单独链接起来。

出于可访问性的目的,我想使用包含文档片段的链接,因此:

<a href="#quicklinks" id="quicklinks-trigger">Quick Links</a>

使用相应的 JavaScript(使用 jQuery):

$("#quicklinks-trigger").click(function(e){ 
 $("#shadow").removeClass("default");
 $("#shadow").addClass("active");
});

#quicklinks HREF 将屏幕阅读器的内部光标(又名插入符号)重定向到新显示的 UI 的开头。 “快速链接”子窗口中有一个相应的链接,它将光标重定向回文档的主要部分()。您可以在测试用例 1 中看到这一点。如果您使用屏幕阅读器收听(我正在使用 NVDA 进行测试),则触发链接时屏幕阅读器会很高兴地跳到快速链接,然后返回到主文档当快速链接关闭链接被触发时。

它还会根据文档片段上下滚动页面,这是丑陋且烦人的。可以使用 window.preventDefault() 来抑制这种情况 - 请参阅测试用例 2,它工作得非常顺利并且不会在文档中滚动,因此:

$("#quicklinks-trigger").click(function(e){ 
 $("#shadow").removeClass("default");
 $("#shadow").addClass("active");

e.preventDefault(); });

不幸的是,对 PreventDefault() 的调用也会阻止浏览器将光标移动到正确的位置。盲人用户可以在那里触发链接,然后屏幕阅读器将继续按源代码顺序阅读下一项,而不是快速链接 UI。解决这个问题的最简单方法是将定义快速链接子窗口的 HTML 紧接在触发链接之后;但我不能这样做,因为它的目标 CMS 不能很好地处理插入到菜单中的大块 HTML。

我尝试了一些其他方法来消除滚动。测试用例 3 手动向后滚动窗口:

$("#quicklinks-trigger").click(function(e){ 
 $("#shadow").removeClass("default");
 $("#shadow").addClass("active");
 window.setTimeout(function(){ scrollTo(0,0); }, 1); 
});

...它可以工作,但有明显的抖动效果,因为它向下滚动然后向上滚动,所以这并不比测试用例 1 更好。

在测试用例 4 中,我尝试在中使用 PreventDefault()与 focus() 结合,希望手动移动内部光标:

$("#quicklinks-trigger").click(function(e){ 
 $("#shadow").removeClass("default");
 $("#shadow").addClass("active");
 $("#quicklinks").focus();
 e.preventDefault();
});

但它不起作用,因为 #quicklinks 是一个 DIV,而不是可聚焦的元素。我想我可以在快速链接 HTML 中添加一个隐藏的可聚焦元素,但这会很混乱。

在测试用例 5 中,我尝试从目标元素中删除 ID 属性,使用 onhashchange 事件重写片段标识符,然后恢复 ID:

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");
});

这产生了允许滚动但阻止光标移动的不良效果。我认为 ID 交换中的事件顺序是错误的;这应该可以抑制滚动,但我怀疑它是否会允许光标移动。

确实很烦人的是,您无法取消视力正常的用户的滚动,而不同时取消屏幕阅读器用户的光标重定向。

到目前为止,我只使用 Firefox 和 NVDA 进行了测试。我不知道这在浏览器和屏幕阅读器的其他组合中会如何发挥作用。

建议?

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 test cases, but haven't got the reputation points to link them individually yet.

For accessibility purposes, I want to use a link containing a document fragment, thus:

<a href="#quicklinks" id="quicklinks-trigger">Quick Links</a>

With corresponding JavaScript (using jQuery):

$("#quicklinks-trigger").click(function(e){ 
 $("#shadow").removeClass("default");
 $("#shadow").addClass("active");
});

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 (<a href="#main" id="close-quicklinks"></a>). 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.

It also scrolls the page up and down in response to the document fragments, which is ugly and annoying. That can be suppressed using window.preventDefault() -- see Test Case 2, which works very smoothly and doesn't scroll around the document, thus:

$("#quicklinks-trigger").click(function(e){ 
 $("#shadow").removeClass("default");
 $("#shadow").addClass("active");

e.preventDefault();
});

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.

I've tried some other approaches to eliminating the scrolling. Test Case 3 scrolls the window back manually:

$("#quicklinks-trigger").click(function(e){ 
 $("#shadow").removeClass("default");
 $("#shadow").addClass("active");
 window.setTimeout(function(){ scrollTo(0,0); }, 1); 
});

... 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.

In Test Case 4, I tried using preventDefault() in combination with focus() in the hopes of moving the internal cursor manually:

$("#quicklinks-trigger").click(function(e){ 
 $("#shadow").removeClass("default");
 $("#shadow").addClass("active");
 $("#quicklinks").focus();
 e.preventDefault();
});

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.

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:

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");
});

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.

It's really annoying that you can't cancel the scrolling for sighted users without also canceling the cursor redirect for screen reader users.

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.

Suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浅黛梨妆こ 2024-10-08 08:41:53

我想出了一个解决方法,允许使用文档片段链接,允许屏幕阅读器的插入符号重定向,并且不滚动视口。方法是

  1. 在要链接的元素的顶部放置一个隐藏元素
  2. 链接到隐藏元素而不是其后面的内容
  3. 使用固定定位将隐藏元素移动到与视口顶部齐平

这样,当您单击针对隐藏元素的链接,浏览器尝试将屏幕“滚动”到位,但它已经位于视口的顶部,因此不会发生实际的滚动。发生插入符号重定向,因此屏幕阅读器用户可以到达链接指向的位置。

有一些怪癖。在 Opera、Safari 和 Chrome 中,单击以这种方式排列的链接将导致滚动,但前提是用户已经向下滚动。我不知道为什么会这样;也许他们没有更新屏幕左侧固定位置元素的位置?无论如何,此问题仅影响一组高度特定的情况,这些情况可以通过合理的页面布局来避免。所以我认为好处(可访问的、相对简单的代码)超过了缺点(在某些浏览器和环境下的轻微视觉怪癖)。

有关此技术的更完整讨论,请参阅:

http://www.accessifyforum.com/ viewtopic.php?p=77132

希望这对其他人有帮助。

I've come up with a work-around which allows the use of document fragment links, allows for the caret redirect for screen readers, and doesn't scroll the viewport. The method is

  1. Place a hidden element at the top of the element that you are linking to
  2. Link to the hidden element instead of the content that follows it
  3. Use fixed positioning to move the hidden element flush with the top of the viewport

In this way, when you click the link targeting the hidden element, the browser tries to "scroll" the screen into place, but it's already at the top of the viewport, so no actual scrolling takes place. The caret redirect occurs, so screen reader users get to where the link was pointing.

There are a couple of quirks. In Opera, Safari, and Chrome, clicking a link arranged in this way will cause a scroll, but ONLY if the user has already scrolled down. I'm not sure why this is so; perhaps they are not updating the positions of fixed-position elements which are off the left of the screen? In any case, this issue affects only a highly specific set of circumstances which can be mostly avoided through sensible page layout. So I think the benefits (accessible, comparatively simple code) outweigh the disadvantages (minor visual quirk in some browsers and circumstances).

For a more complete discussion of this technique, see:

http://www.accessifyforum.com/viewtopic.php?p=77132

Hope this helps someone else.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文