javascript - 标签可访问的弹出导航的两个问题我使用了一些建议

标签 javascript html css accessibility

我正在尝试为投资组合式网站创建一个可访问的导航菜单。当屏幕小于一定宽度(本演示为 768px)时,水平菜单导航消失并被“汉堡”取代。汉堡的父 div 具有 JavaScript onclick 和 onkeydown 函数,以便当单击或点击汉堡时,或者键盘用户将注意力集中在汉堡上并使用按空格键或 Enter 键时,会从包含垂直导航菜单的一侧打开一个 div“sidenav” .

但是,如果键盘用户继续按 Tab 键,焦点会继续向下移动到导航后面的页面,就好像“sidenav”不存在一样,当 Tab 键最终到达 sidenav 的顶部(它遇到的第一个元素)时是关闭按钮,按 Tab 键会关闭菜单,因此无法访问菜单项。

所以: 问题1:当按下汉堡键时,如何触发焦点“跳转”到新打开的导航?

问题 2:如何使“关闭”按钮忽略 Tab 键并仅使用空格键或 Enter 键?

这是我的菜单的简化版本(您可能需要全屏才能看到水平菜单)。

/* detect keyboard users */
function handleFirstTab(e) {
    if (e.keyCode === 9) { // the "I am a keyboard user" key
        document.body.classList.add('user-is-tabbing');
        window.removeEventListener('keydown', handleFirstTab);
    }
}
window.addEventListener('keydown', handleFirstTab);

/*  Open Sidenav 
-------------------*/
function openNav() {
    let element = document.querySelector('ul.menucontent');
    if (element.classList.contains('menucontent')) {
    element.classList.remove('menu-a');
    element.classList.add('menu-b');
    };
    let element3 = document.querySelector('div.sidenav');
    let element4 = document.querySelector('.closebtn');
    if (element3.classList.contains('sidenav')) {
    element3.style.width = "350px";
    element4.style.visibility = "visible";
    };
  document.getElementById('vmenu').focus();
}
function closeNav() {
    let element = document.querySelector('ul.menucontent');
    if (element.classList.contains('menucontent')) {
    element.classList.remove('menu-b');
    element.classList.add('menu-a');
    };
    let element3 = document.querySelector('div.sidenav');
    let element4 = document.querySelector('.closebtn');
    if (element3.classList.contains('sidenav')) {
    element3.style.width = "0";
    element4.style.visibility = "hidden";
    };
}
// Toggle content  
    for (const selector of [".toggle-btn",]) {
        const toggleButtons = [...document.querySelectorAll(selector)];
        for (const toggleButton of toggleButtons) {
            toggleButton.addEventListener('click', () => {
                toggleButtons.filter(b => b !== toggleButton).forEach(b => {
                    b.nextElementSibling.classList.remove('reveal-content');
                });
                toggleButton.nextElementSibling.classList.toggle('reveal-content');
            });
        };
    }
    for (const selectorTwo of [".close-btn",]) {
        const closeButtons = [...document.querySelectorAll(selectorTwo)];
        for (const closeButton of closeButtons) {
            closeButton.addEventListener('click', () => {
                closeButton.parentElement.classList.toggle('reveal-content');
            });
        };
    }
body.user-is-tabbing button > a:focus {
  border: none;
}
body:not(.user-is-tabbing) a:focus,
body:not(.user-is-tabbing) button:focus,
body:not(.user-is-tabbing) input:focus,
body:not(.user-is-tabbing) select:focus,
body:not(.user-is-tabbing) textarea:focus {
  outline: none;
}
.container-fluid, 
.container {
  margin-right: auto;
  margin-left: auto;
  width: 100%;
}
.d-block
.d-none {
  display: none;
}
.sidenav {
  height: 100%;
  width: 0;
  position: fixed;
  z-index: 996;
  top: 0;
  left: 0;
  background-color: #fff;
  overflow-x: hidden;
  transition: 0.5s;
  padding: 1rem 0 0;
  box-shadow: 0 2px 5px #acaaaa;
}
.trigram {
  position: relative;
  top: 0;
  left: 0;
  margin-bottom: 1rem;
  padding: 0;
  background: transparent;
  z-index: 995;
  width: 2rem;
}
.burger {
  position: relative;
  border-top: 0.15rem solid green;
  border-bottom: 0.15rem solid green;
  background: transparent;
  height: 1.5rem;
  width: 2rem;
}
.burger::after {
  position: absolute;
  content: "";
  border-top: 0.15rem solid green;
  top: 40%;
  left: 0;
  width: 2rem;
}
.sidemenu {
  position: relative;
  top: 5rem;
}
.mm ul {
  list-style: none;
}
.mm li {
  margin: 1rem 0;
  padding: 0 0 0 1rem;
}
.mm .menucontent.menu-a {
  display: none;
}
.mm .menucontent.menu-b {
  display: flex;
  display: -webkit-flex;
  flex-direction: column;
  justify-content: normal;
  margin: 0 0 1rem;
  padding: 0;
  position: relative;
  top: 0;
  z-index: 997;
  overflow-y: auto;
  }
.closebtn {
  border-bottom: none;
  font-size: 2.25rem;
  margin: 0;
  position: absolute;
  top: 2rem;
  right: 2rem;
  z-index: 998;
}
@media only screen and (min-width: 768px){
  .d-none {
    display: none;
  }
  .d-md-block {
    display: block;
  }
  .trigram {
    display: none;
  }
  .mm .menucontent.menu-a {
    position: relative;
    padding: 0;
    margin: 0 auto;
    white-space: nowrap;
    display: flex;
  }
  .mm .menucontent.menu-a,
  .mm .menucontent.menu-b {
    flex-direction: row;
    justify-content: center;
  }
  .mm li {
    padding: 0 0.5rem;
  }
   .main-menu-container {
    border-top: 2px solid green;
    border-bottom: 2px solid green;
    padding: 0.5rem 0;
    margin: 1rem 0;
  }
}
<div id="sidenav" class="sidenav">
    <div id="closebtn" class="closebtn">
        <a href="javascript:void(0)" onclick="closeNav()" onkeydown="closeNav()" role="button" tabindex="0" aria-label="close navigation">&times;</a>
    </div>
    <div id="vmenu" class="sidemenu d-md-none mm">
        <nav aria-label="Main Navigation" class="menuouter ">
            <ul class="menucontent menu-a" role="menubar">
                <li class="item-101 default current active single top-level" role="none" tabindex="-1">
                    <a href="#" title="Side menu Home" class="icon-home">Side menu Home</a>
                </li>
                <li class="item-128 single" role="none" tabindex="-1">
                    <a href="#" title="Side menu page 2">Side menu page 2</a>
                </li>
            </ul>
        </nav>
    </div>
</div>
<div class="container-fluid menu-outer d-block d-md-none">
    <div id="trigram" class="trigram" role="button" tabindex="0" aria-label="open navigation" aria-controls="sidenav" aria-haspopup="true" onclick="openNav()" onkeydown="openNav()">
        <div class="burger" style="cursor:pointer" >&nbsp;</div>
    </div>
</div>
<div class="container-fluid d-none d-md-block">
    <div class="main-menu-container">
        <div id="hmenu" class="row d-none d-md-block main-menu mm">
            <nav aria-label="Main Navigation" class="menuouter ">
                <ul class="menucontent menu-a" role="menubar">
                    <li class="item-101 default current active single top-level" role="none" tabindex="-1">
                        <a href="#" title="Horizontal menu Home" class="icon-home">Horizontal menu Home</a>
                    </li>
                    <li class="item-128 single" role="none" tabindex="-1">
                        <a href="#" title="Horizontal menu page 2">Horizontal menu page 2</a>
                    </li>
                </ul>
            </nav>
        </div>
    </div>
</div>
<div>This is some text. It has a link in it: <a href="#">This is the first link</a></div>
<div>Here is some more text with more links. It has a link in it: <a href="#">This is the second link</a>. Integer mauris sem, convallis ut, consequat in, sollicitudin sed, leo.</div>
<div>Sed lacus velit, consequat in, ultricies sit amet, malesuada et, diam. Integer mauris sem, convallis ut, consequat in, sollicitudin sed, leo. <a href="#">This is the third link </a>Cras purus elit, hendrerit ut, egestas eget, sagittis at, nulla. Integer justo dui, faucibus dictum, convallis sodales, accumsan id, risus. Aenean risus. Vestibulum scelerisque placerat sem.</div>

最佳答案

关于“焦点捕获”的好文章:https://medium.com/@im_rahul/focus-trapping-looping-b3ee658e5177
这是一个可能有帮助的 stackoverflow 答案:Vanilla javascript Trap Focus in modal (accessibility tabbing )

这就是我对模态框的做法:

const btnOpenEmailSignup = document.getElementById('env'); //This is the button that opens the modal
const modalOverlay = document.getElementById('modalOpenEmailSignup'); //Modal specific--won't need!
const btnClose = document.getElementById('close'); //Modal specific--won't need!
let focusedElementBeforeModal;
const toggleModal = function modalToggel() {
  modalOverlay.classList.toggle('show-modal'); //Modal specific--won't need!

  // ***** Trap focus ***** //
  // Save current focus--*You might not need this*--
  focusedElementBeforeModal = document.activeElement;

  // Listen and trap the keyboard
  modal.addEventListener('keydown', trapTabKey);

  // Find all focusable children (not all of these will be needed, but keeping them in shouldn't hurt)
  const focusableElementsString = 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable]';
  let focusableElements = modal.querySelectorAll(focusableElementsString);

  // convert NodeList to Array
  focusableElements = Array.prototype.slice.call(focusableElements);
  const emailField = document.getElementById('email'); //This const is the one that will get focus on opening the modal.
  const firstTabStop = focusableElements[0];
  var lastTabStop = focusableElements[focusableElements.length - 1];

  // Focus to email field
  emailField.focus();

  function trapTabKey(e) {
    // Check for tab key press
    if (e.keyCode === 9) {
      // SHIFT + TAB
      if (e.keyShift) {
        if (document.activeElement === firstTabStop) {
          e.preventDefault();
          lastTabStop.focus();
        }
      // TAB
      } else {
        if (document.activeElement === lastTabStop) {
          e.preventDefault();
          firstTabStop.focus();
        }
      }
    }
  }
  // ***** Trap focus end ***** //

一个注意事项:这似乎只在一个方向上起作用(“向下”,按 Tab 键,而不是“向上”,按 Shift+Tab)。目前还无法使其以其他方式工作。

关于javascript - 标签可访问的弹出导航的两个问题我使用了一些建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66080384/

相关文章:

javascript - HTML :How to check whether the file is exist in local PC or not using javascript

jquery - 使用 jquery "keydown"移动 "box"

html - 在表内 float 不工作

html - 如何在一个 html 页面中显示两个或多个 Css 加载器

javascript - jQuery 无法从 $(this) 按钮单击获取 id

javascript - jQuery:在使用 .on() 和 .click() 加载 DOM 后单击 Chrome

javascript - JQuery UI 拖放(获取 Draggable 值以显示和隐藏文本区域框)

javascript - 如何在不离开页面的情况下发送表单?

javascript - 如何在静态时隐藏 Chromium 中的滚动条,但在滚动时显示?

html - 如何使按钮旁边的图像链接内联?