我为 WordPress 创建了一个自定义 Nav Walker,以将正确的 ARIA 角色添加到 wp_nav_menu()
的输出中。功能。检查出来没问题。但我一直在尝试做两件事。
我的步行器产生以下输出:
<nav id="siteNav" role="navigation">
<ul id="menuMain" class="menu" role="menubar">
<li id="menu-item-1698" class="menu-item" role="presentation">
<a href="http://localhost/" role="menuitem">Front Page</a>
</li>
<li id="menu-item-1697" class="menu-item" role="presentation">
<a href="http://localhost/blog/" role="menuitem">Blog</a>
</li>
<li id="menu-item-1694" class="menu-item" role="presentation">
<a href="http://localhost/sample-page/" role="menuitem">Sample Page</a>
</li>
<li id="menu-item-1695" class="menu-item" role="presentation">
<a href="http://localhost/page-b/" role="menuitem">Page B</a>
</li>
<li id="menu-item-1696" class="menu-item" role="presentation">
<a href="http://localhost/page-a/" role="menuitem">Page A</a>
</li>
<li id="menu-item-1699" class="menu-item" role="presentation">
<a href="http://localhost/" role="menuitem">Front Page</a>
</li>
<li id="menu-item-1701" class="menu-item" role="presentation">
<a href="http://localhost/level-1/" role="menuitem">Level 1</a>
<ul class="sub-menu" role="menu" aria-expanded="false">
<li id="menu-item-1702" class="menu-item" role="presentation">
<a href="http://localhost/level-1/level-2b/" role="menuitem">Level 2b</a>
</li>
<li id="menu-item-1703" class="menu-item" role="presentation">
<a href="http://localhost/level-1/level-2a/" role="menuitem">Level 2a</a>
</li>
<li id="menu-item-1704" class="menu-item" role="presentation">
<a href="http://localhost/level-1/level-2/" role="menuitem">Level 2</a>
<ul class="sub-menu" role="menu" aria-expanded="false">
<li id="menu-item-1705" class="menu-item" role="presentation">
<a href="http://localhost/level-1/level-2/level-3b/" role="menuitem">Level 3b</a>
</li>
<li id="menu-item-1706" class="menu-item" role="presentation">
<a href="http://localhost/level-1/level-2/level-3a/" role="menuitem">Level 3a</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
我现在想做的是将某种 ID 添加到 <a>
元素是 <ul class="sub-menu">
的同级元素元素并在 aria-labelledby
中引用该 ID属性。
因此包含子菜单的菜单项将如下所示:
<li id="menu-item-1704" class="menu-item" role="presentation">
<a href="http://localhost/level-1/level-2/" role="menuitem" id="{ID}">Level 2</a>
<ul class="sub-menu" role="menu" aria-expanded="false" aria-labelledby="{ID}">
<li id="menu-item-1705" class="menu-item" role="presentation">
<a href="http://localhost/level-1/level-2/level-3b/" role="menuitem">Level 3b</a>
</li>
<li id="menu-item-1706" class="menu-item" role="presentation">
<a href="http://localhost/level-1/level-2/level-3a/" role="menuitem">Level 3a</a>
</li>
</ul>
</li>
我的助行器的代码:
类 Walker_ARIA_Nav_Menu 扩展了 walker {
public $tree_type = array( 'post_type', 'taxonomy', 'custom' );
public $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent<ul class=\"sub-menu\" role=\"menu\" aria-expanded=\"false\" aria-hidden=\"true\">\n";
}
public function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "$indent</ul>\n";
}
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
$args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args, $depth );
$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
$output .= $indent . '<li' . $id . $class_names .' role="presentation">';
$atts = array();
$atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : '';
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
$atts['href'] = ! empty( $item->url ) ? $item->url : '';
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
$title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );
$item_output = $args->before;
$item_output .= '<a'. $attributes .' role="menuitem">';
$item_output .= $args->link_before . $title . $args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
public function end_el( &$output, $item, $depth = 0, $args = array() ) {
$output .= "</li>\n";
}
} // End Walker_ARIA_Nav_Menu Class
最佳答案
我将回答这个问题,假设您正在为网站或类似网站构建此菜单(而不是您在所选操作系统上安装的应用程序,该应用程序的行为应该与 native 操作系统菜单相同)。
话虽这么说,我相信您在这里遇到了一个整体 ARIA 问题,这使得您问题中的 PHP 部分变得毫无意义。
立即考虑,给出您建议的以下 HTML:
<ul class="sub-menu" role="menu" aria-expanded="false" aria-labelledby="{ID}">
<li id="menu-item-1705" class="menu-item" role="presentation">
<a href="http://localhost/level-1/level-2/level-3b/" role="menuitem">Level 3b</a>
</li>
<li id="menu-item-1706" class="menu-item" role="presentation">
<a href="http://localhost/level-1/level-2/level-3a/" role="menuitem">Level 3a</a>
</li>
</ul>
…您应该跳过aria-labelledby
。由于该元素上没有制表位(我不是指 tabindex
),因此屏幕阅读器没有理由宣布它,因此它不会。此外,如果它确实有制表位,则 aria-labelledby 会覆盖该元素上可能存在的可访问名称。 From the horse's mouth :
The specified behavior of aria-labelledby is that the associated label text is announced instead of the link text (not in addition to the link text). When the link text itself should be included in the label text, the ID of the link should be referenced as well in the string of IDs forming the value of the aria-labelledby attribute.
现在谈谈整个方法。我建议您根本不要在这里使用 role="menu"
或 role="menuitem"
。使用它们可以让屏幕阅读器用户期望整个菜单将充当他/她的操作系统中的菜单栏。我不知道您是否已准备好所有必要的键盘交互来实现这一点,但根据我的经验,这种情况很少发生。
如果您不同意我的观点,请查看以下一些来源......
Menu widgets must provide keyboard support to navigate all the menu items in the menu. Keyboard support for a menu typically include the cursor keys to navigate between the menu items and open and close popupmenus.
然后,它继续描述您需要映射的所有键盘交互,并提供一个示例 HTML block 。您可能会注意到,它不会按照您使用 ARIA 属性的方式使用它们。
这种菜单出现在WebAIM mailing list上经常。这是 one of many discussions 的摘录:
But to take a step back, it may be first useful to ensure that an ARIA menubar is actually appropriate. This is not typically appropriate for web site navigation - it's intended for a web application's menu bar (think "File...", "Edit...", etc.).
如果你看一下当前最先进的可访问菜单,这个就是 accessible mega-menu from Adobe ,您将看到 Adobe 明确说明了它不使用 role="menu"
也不使用 role="menuitem"
的原因:
We don't use
role="menu"
for the menu container androle="menuitem"
for each of the links therein, because if we do, assistive technology will no longer interpret the links as links, but instead, as menu items, and the links in our global navigation will no longer show up when a screen reader user executes a shortcut command to bring up a list of links in the page.
最后,我鼓励您构建理想菜单的静态 HTML 版本,然后使用屏幕阅读器进行测试。您可以获得 NVDA for Windows 的副本免费(尽管 you really should donate ),并且 VoiceOver 已预装在 Mac 上。
顺便说一句,WordPress has a support forum dedicated to accessibility ,所以你也可以在那里问。
关于php - 使用 WordPress 创建正确的 ARIA 菜单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37715775/