实用的JavaScript可访问性

本文将向您展示您现在可以执行的一些简单操作,以使您的JavaScript更加易于使用。 这不是尖端技术,而是我们多年来一直在做的事情。 这篇文章扩展了我们的介绍性文章“ JavaScript Accessibility 101”

三大核心原则

JavaScript的可访问性归结为三个核心原则:

  • 所有JavaScript功能都必须采用可解释为文本的形式。
  • 键盘必须访问所有JavaScript功能。
  • JavaScript中基于时间的活动应该是用户可控制的,除非那样会改变其含义。

让我们采用这些原则中的每一个,然后看看我们可以做些实际的事情来实现它。

文字解释

该原理的重点是将信息表示为具有有意义结构的文本,可以通过编程确定该结构 。 实体元素语义应该是所有交互内容的基础,但是对于辅助技术尤其如此。

有视力的用户并不总是会受到语义的影响–菜单是菜单,因为它看起来像菜单,无论它是基于列表还是<div>构建的。 但是盲人用户只能理解其屏幕阅读器可以解释的内容–菜单是菜单,因为它是结构化链接的层次结构。 例如,如果我们正在构建一个选项卡框,它可能类似于以下示例。 注意如何使用各种语义标记。

<div class="box">
  <section class="panel">
    <h3 class="tab" tabindex="0">Section 1</h3>
    <p class="content">This is the content for Section 1</p>
  </section>
  <section class="panel">
    <h3 class="tab" tabindex="0">Section 2</h3>
    <p class="content">This is the content for Section 2</p>
  </section>
</div>

使信息以编程方式可访问也很重要。 这意味着使用标准DOM函数向页面添加新内容,而不是使用document.write()innerHTML

innerHTML无疑是方便的,并且通常比逐节点添加新内容要快得多。 innerHTML的问题在于浏览器经常更改标记,因此生成的DOM与您指定的DOM不同。 在极少数情况下,以这种方式添加的内容根本不会出现在DOM中。

要解决此问题,请通过中间未添加的元素添加HTML,如下所示。 要使用此功能,请向其传递HTML字符串和目标元素引用。 该函数创建一个虚拟DOM,然后将其节点附加到目标。

function appendHTML(target, html)
{
  var fragment = document.createElement('div');
  fragment.innerHTML = html;

  while(fragment.hasChildNodes())
  {
    target.appendChild(fragment.firstChild);
  }

  return target;
}

键盘辅助功能

使键盘可以访问交互式内容时,请坚持使用一组核心键: TabEnter ,四个箭头键Escape 。 这些键应按原样使用,即不必按住Shift键或其他修饰键。 如果确实需要使用其他键或修饰键击,则应向用户提供说明。 但是,仍然最好避免使用Alt组合,因为它们用于本机菜单快捷方式。

大多数键还具有默认的浏览器操作,有时必须阻止默认键,以防止行为冲突。 例如,在下拉菜单中使用向上键和向下键时,您不希望它们同时滚动页面。 执行此操作的标准方法是使用preventDefault() ,如以下示例所示,该示例来自菜单脚本:

menu.addEventListener('keydown', function(e)
{
  if(/^(3[789]|40)$/.test(e.keyCode.toString()))
  {
    switch(e.keyCode)
    {
      case 37:
        //... handle left-arrow
        break;
      case 38:
        //... handle up-arrow
        break;
      case 39:
        //... handle right-arrow
        break;
      case 40:
        //... handle down-arrow
        break;
    }

    e.preventDefault();
  }
}, false);

如果keyCode与箭头键匹配,则该函数将视情况处理该键,然后调用preventDefault() 。 如果按下任何其他键,则事件将被忽略,并保持默认行为。 注意不要挡住Tab键,否则将引起用户关注!

请注意,上面的示例使用keydown而不是keypress ,因为大多数浏览器不会(也不应该)触发控制键的keypress事件。 如果按住键,则keydown事件也会连续触发,因此在某些情况下,您可能更喜欢使用keyup ,这种情况不会重复出现,但不能阻止默认操作。

另一个重要的考虑因素是确保我们保持逻辑的内容顺序 。 例如,当使用丰富的工具提示时,必须将它们直接插入触发它们的元素之后,以便您可以使用Tab键切换至它们,以便屏幕阅读器接下来可以阅读它们。 例如,一个简单的工具提示可能看起来像这样:

位于链接词上方的丰富工具提示。

位于链接词上方的丰富工具提示。

您可以看到主要工具提示文本的周围带有方括号,而底部的链接具有方括号和定界管道符号。 文本也包裹在<em>以增加语义重点。 禁用CSS时,内容如下所示:

在没有CSS的情况下查看了相同的工具提示,并在括号内显示了说明。

在没有CSS的情况下查看了相同的工具提示,并在括号内显示了说明。

这是该示例的HTML:

<blockquote>
  <p>
    Assistive technologies can derive information
    from their attributes and text; for example, a
    dynamic menu would be made using links organised
    into nested lists, in which the menu levels are
    denoted by the hierarchy, and by the use of
    <span id="context">
      <a href="http://www.maxdesign.com.au/2006/01/17/about-structural-labels/"
         title="descriptive headings used to indicate the main components of a web page, such as global site navigation, local navigation and footer information">
        structural labels
      </a>
    </span>
    around each top-level link.
  </p>
</blockquote>

链接周围的<span>提供了插入目标​​,因此可以在链接后直接添加工具提示。 它还为工具提示的绝对位置提供了相对上下文:

#context
{
  position:relative;
}
#context > span.tooltip
{
  position:absolute;
  bottom:1.7em;
  right:0;
}

#context > span.tooltip
{
  width:18em;
  padding:6px 8px;
  white-space:normal;
  border:1px solid #555;
  font:normal normal normal 0.85em/1.4 arial,sans-serif;
  text-align:right;
  background:#ffd;
  box-shadow:1px 2px 3px -1px rgba(0,0,0,0.5);
}
#context > span.tooltip > em
{
  display:block;
  padding:4px 4px 8px 4px;
  text-align:left;
  font-style:normal;
}

这是该示例的JavaScript:

var
infotext,
tooltip = null,
context = document.getElementById('context'),
trigger = context.getElementsByTagName('a').item(0);

trigger.addEventListener('click', function(e)
{
  if(tooltip === null)
  {
    infotext = trigger.getAttribute('title');
    trigger.removeAttribute('title');

    tooltip = document.createElement('span');
    tooltip.className = 'tooltip';

    var info = tooltip.appendChild(document.createElement('em'));
    info.appendChild(document.createTextNode(' (' + infotext + ') '));

    tooltip.appendChild(document.createTextNode('[ '));

    var more = tooltip.appendChild(document.createElement('a'));
    more.setAttribute('href', trigger.getAttribute('href'));
    more.appendChild(document.createTextNode('reference'));

    tooltip.appendChild(document.createTextNode(' | '));

    var google = tooltip.appendChild(document.createElement('a'));
    google.setAttribute('href', 'http://www.google.com/search?q=Structural+Labels');
    google.appendChild(document.createTextNode('search'));

    tooltip.appendChild(document.createTextNode(' ]'));

    tooltip = context.appendChild(tooltip);
  }
  else
  {
    trigger.setAttribute('title', infotext);

    context.removeChild(tooltip);
    tooltip = null;
  }

  e.preventDefault();
}, false);

在这种情况下,将使用preventDefault()来阻止单击链接触发(或删除)工具提示时的链接。 这就是为什么工具提示还包括原始参考链接的原因,因此与静态标记相比,内容不会丢失。

控制基于时间的活动

JavaScript使用的最常见的基于时间的活动是内容动画。 重要的是要确保动画具有暂停按钮,并且在理想情况下,这是查看完整显示内容的方法。 例如,可以这样构建滚动的新闻自动收录器:

<div id="ticker">
  <ol>
    <li><a href="...">This is the first news item</a></li>
    <li><a href="...">This is the second news item</a></li>
  </ol>
</div>
<div id="buttons">
  <button id="pause-button" type="button">Pause</button>
  <button id="expand-button" type="button">Expand</button>
</div>

标记是有序列表,因为新闻项目通常是按时间排序的,最新的标题在顶部。 该示例的CSS将如下所示:

#buttons
{
  display:none;
}
#buttons.script-enabled
{
  display:block;
}

#ticker.script-enabled,
#ticker.script-enabled > ol
{
  position:relative;
}

#ticker
{
  white-space:nowrap;
  overflow:hidden;
  margin:5px 0 0 0;
  padding:5px 10px;
  border:2px solid #555;
  background:#f2f2f2;
}
#ticker.script-enabled > ol,
#ticker.script-enabled > ol > li
{
  margin:0;
  padding:0;
  list-style-type:none;
}
#ticker.script-enabled > ol > li
{
  display:inline-block;
  margin-right:20px;
}

#ticker.script-enabled.expanded,
#ticker.script-enabled.expanded > ol
{
  position:static;
}
#ticker.script-enabled.expanded
{
  white-space:normal;
  overflow:hidden;
}

尽管以下JavaScript将所有内容整合在一起:

var
container = document.getElementById('ticker'),
list = container.getElementsByTagName('ol').item(0),
buttons = document.getElementById('buttons'),
pauser = document.getElementById('pause-button'),
expander = document.getElementById('expand-button');

buttons.className = 'script-enabled';
container.className = 'script-enabled';

var scrollwidth = 0;
var items = list.getElementsByTagName('li');
for(var i = 0; i < items.length; i ++)
{
  scrollwidth += items[i].offsetWidth + 20;
}

var scrollstart = container.offsetWidth;
list.style.left = scrollstart + 'px';

var
timer = null,
moving = false,
scrolloffset = scrollstart;

function pause()
{
  moving = false;
  window.clearInterval(timer);
  timer = null;
}

function resume()
{
  moving = true;
  timer = window.setInterval(function()
  {
    scrolloffset -= 5;
    if(scrolloffset < (0 - scrollwidth))
    {
      scrolloffset = scrollstart;
    }
    list.style.left = scrolloffset + 'px';
  }, 100);
}

pauser.addEventListener('click', function()
{
  if(moving)
  {
    pause();
    pauser.firstChild.nodeValue = 'Resume';
  }
  else
  {
    resume();
    pauser.firstChild.nodeValue = 'Pause';
  }
}, false);

expander.addEventListener('click', function()
{
  pause();
  container.className = 'expanded';
  pauser.parentNode.removeChild(pauser);
  expander.parentNode.removeChild(expander);
}, false);

resume();

需要注意的重要一点是, buttons容器默认情况下是隐藏的,仅在添加了script-enabled类时才显示。 这样一来,当在不使用JavaScript的情况下查看页面时,不会为用户留下无法执行任何操作的按钮。

同样,仅当添加了script-enabled类时,适用于overflow的规则和将列表转换为水平滚动条的其他属性才生效。 这是必要的,因为默认情况下,这些样式会遮挡大多数内容,因此,除非脚本存在,否则我们需要确保不会发生这种情况。

Pause按钮将停止滚动,因此您可以在自己的时间内阅读每个项目,然后更改为“ Resume以便再次启动它。 Expand按钮也将停止滚动,但是会添加一个expanded类,该类将覆盖overflow和其他布局样式。 这使内容变成了静态链接列表。

结论

这是实际的JavaScript可访问性的旋风之旅! 但是,如果有一件我想让您拿走的东西,那就是JavaScript的可访问性并不难 。 它只需要注意三个核心原则。 下次,我将继续使用更高级的技术,例如漫游tabindex ,拖放和可访问的Ajax!

From: https://www.sitepoint.com/practical-javascript-accessibility/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值