2

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

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

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

问题 2:如何使“关闭”按钮忽略制表符,仅使用空格键或回车键?

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

/* 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>

4

3 回答 3

2

问题 2:如何使“关闭”按钮忽略制表符,仅使用空格键或回车键?

从这个问题开始,因为它更复杂,我认为它与给定问题文本的其余部分的“如何在我的菜单中捕获焦点”相同。

你会经常看到人们通过拦截Tabkey 和Shift+Tab键来捕获焦点,但不做任何其他事情的例子。

问题是这对屏幕阅读器用户不起作用,因为他们使用快捷方式通过标题、链接、部分等进行导航。

因此,我们必须对屏幕阅读器隐藏除菜单之外的所有其他内容。

大部分工作都可以aria-hidden="true"<main><aside><footer>元素等上完成,以隐藏所有页面内容。

但是我们仍然有问题,任何可以接收焦点的元素(按钮、超链接等)仍然是可聚焦的,因此忽略aria-hidden

为此,我们需要添加tabindex="-1"到页面上的每个可聚焦元素,但菜单中的元素除外。

菜单也应该可以通过Esc键关闭。

最后,当菜单关闭时,焦点应该返回到打开它的按钮上,如果通过Esc键关闭菜单,这一点尤其重要,因为文档焦点将丢失。

下面的示例有点混乱,但它应该涵盖所有要点。我已经评论了每个项目存在的原因以及它的作用,希望它是有意义的。

当您打开菜单时,检查页面上的其他项目以查看它们是否都已tabindex="-1"添加到其中。

/////////////////////////////////////////HIDING ALL OTHER CONTENT FROM SCREEN READERS///////////////////////////////////
var content = document.getElementById('contentDiv');
var menuBtn = document.querySelector('.open-menu');
var closeMenuBtn = document.querySelector('.close-menu');
var menu = document.querySelector('.menu');
var focusableItems = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', '[tabindex]:not([disabled])', '[contenteditable=true]:not([disabled])'];

//the main function for setting the tabindex to -1 for all children of a parent with given ID (and reversing the process)
function hideOrShowAllInteractiveItems(parentDivID){  

  //build a query string that targets the parent div ID and all children elements that are in our focusable items list.
  var queryString = "";
  for (i = 0, leni = focusableItems.length; i < leni; i++) {
    queryString += "#" + parentDivID + " " + focusableItems[i] + ", ";
  }
  queryString = queryString.replace(/,\s*$/, "");
      
  var focusableElements = document.querySelectorAll(queryString);      
  for (j = 0, lenj = focusableElements.length; j < lenj; j++) {
            
    var el = focusableElements[j];
    if(!el.hasAttribute('data-modified')){ // we use the 'data-modified' attribute to track all items that we have applied a tabindex to (as we can't use tabindex itself).
            
      // we haven't modified this element so we grab the tabindex if it has one and store it for use later when we want to restore.
      if(el.hasAttribute('tabindex')){
        el.setAttribute('data-oldTabIndex', el.getAttribute('tabindex'));
      }
              
      el.setAttribute('data-modified', true);
      el.setAttribute('tabindex', '-1'); // add `tabindex="-1"` to all items to remove them from the focus order.
              
    }else{
      //we have modified this item so we want to revert it back to the original state it was in.
      el.removeAttribute('tabindex');
      if(el.hasAttribute('data-oldtabindex')){
        el.setAttribute('tabindex', el.getAttribute('data-oldtabindex'));
        el.removeAttribute('data-oldtabindex');
      }
      el.removeAttribute('data-modified');
    }
  }
}


var globalVars = {};


function openMenu(){
     menu.classList.add("open");
     menuBtn.setAttribute('aria-expanded', true);
     
     //get all the focusable items in our menu and keep track of the button that opened the menu for when we close it again.
     setFocus(menuBtn, 'menu');
     
     content.setAttribute("aria-hidden", true);
}

function closeMenu(){
    //close menu
    //unhide the main content
    content.setAttribute("aria-hidden", false);
    //hide the menu
     menu.classList.remove("open");
     // set `aria-expanded` - important for screen reader users.
     menuBtn.setAttribute('aria-expanded', false);
     //set focus back to the button that opened the menu if we can
     if (globalVars.beforeOpen) {
        globalVars.beforeOpen.focus();
     }
}




//toggle the menu
menuBtn.addEventListener('click', function(){
  //use our function to add the relevant `tabindex="-1"` to all interactive elements outside of the menu.
  hideOrShowAllInteractiveItems('contentDiv');
  //check if the menu is open, if it is close it and reverse everything.
  openMenu();
});

closeMenuBtn.addEventListener('click', function(){
  //use our function to add the relevant `tabindex="-1"` to all interactive elements outside of the menu.
  hideOrShowAllInteractiveItems('contentDiv');
  //check if the menu is open, if it is close it and reverse everything.
  closeMenu();
});

//////////////////////////////////TRAPPING FOCUS//////////////////////////////////



var setFocus = function (item, className) { //we pass in the button that activated the menu and the className of the menu list, your menu must have a unique className for this to work.

    className = className || "content"; //defaults to class 'content' in case of error ("content" being the class on the <main> element.)
    globalVars.beforeOpen = item; //we store the button that was pressed before the modal opened in a global variable so we can return focus to it on modal close.

    var findItems = [];
    for (i = 0, len = focusableItems.length; i < len; i++) {
        findItems.push('.' + className + " " + focusableItems[i]); //add every focusable item to an array.
    }
    // finally add the open button to our list of focusable items as it sits outside our menu list. 
    


    var findString = findItems.join(", ");
    globalVars.canFocus = Array.prototype.slice.call(document.querySelectorAll(findString)); 
    if (globalVars.canFocus.length > 0) {
        globalVars.canFocus[0].focus(); //***set the focus to the first focusable element within the modal
        globalVars.lastItem = globalVars.canFocus[globalVars.canFocus.length - 1]; //we also store the last focusable item within the modal so we can keep focus within the modal. 
    }
}

//listen for keypresses and intercept both the Esc key (to close the menu) and tab and shift tab while the menu is open so we can manage focus.
document.onkeydown = function (evt) {
    evt = evt || window.event;
    if (evt.keyCode == 27) {
        //unhide the main content - exactly the same as in the btn event listener.
     hideOrShowAllInteractiveItems('contentDiv');
     closeMenu();
    }
  if (menu.classList.contains('open') && evt.keyCode == 9) { //global variable to check any modal is open and key is the tab key
        if (evt.shiftKey) { //also pressing shift key
            if (document.activeElement == globalVars.canFocus[0]) { //the current element is the same as the first focusable element
                evt.preventDefault();
                globalVars.lastItem.focus(); //we focus the last focusable element as we are reverse tabbing through the items.
            }
        } else {
        console.log(document.activeElement, globalVars.lastItem);
            if (document.activeElement == globalVars.lastItem) { //when tabbing forward we look for the last tabbable element 
                evt.preventDefault();
                
                globalVars.canFocus[0].focus(); //move the focus to the first tabbable element.
            }
        }
    }
};
.menu{
display: none;
}

.menu.open{
   display: block;
}
<header>
    <button class="open-menu">Menu</button>
    <nav>
    <ul class="menu">
        <li><button class="close-menu">Close Menu</button></li>
        <li><a href="https://google.com">Google</a></li>
        <li><a href="https://google.com">Google again</a></li>
        <li><a href="https://google.com">Google once more</a></li>
    </ul>
    </nav>
</header>
<div id="contentDiv">
  



  <main>
  <p>Some information</p>
  <input />
  <button>a button</button>
  </main>
  <footer>
  <button tabindex="1">a button with a positive tabindex that needs restoring</button>
  </footer>
</div>

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

不要这样做,而是将焦点留在原处,并使打开菜单的按钮成为可聚焦项目的一部分。

还要确保切换aria-expanded="true"以让屏幕阅读器知道单击该按钮已展开一些附加信息。我在示例中也这样做了。

于 2021-02-07T01:05:52.150 回答
2

关于“焦点捕获”的好文章: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 ***** //

注意事项:这似乎只在一个方向上起作用(“向下”,使用制表符,而不是“向上”,使用 shift+tab)。还不能让它以另一种方式工作。

于 2021-02-06T20:23:00.393 回答
0

经过大量代码摆弄以根据我的特定要求自定义上述两个答案 - 非常感谢Graham Ritchie的指导- 以及提供类似答案但代码较少的AVD的指导- 我设法让代码完全按照我想要,包括只使用 CSS 类而不使用 ID 以避免潜在的重复 ID。

// detect keyboard users
function handleFirstTab(e) {
    if (e.key === "Tab") { // the "I am a keyboard user" key
        document.body.classList.add('user-is-tabbing');
        window.removeEventListener('keydown', handleFirstTab);
    }
}
window.addEventListener('keydown', handleFirstTab);
/////////////////////HIDING ALL OTHER CONTENT FROM SCREEN READERS///////////////////////
/// `var` changed to `let`
let content = document.querySelector('.mainContent');
let menuBtn = document.querySelector('.open-menu');
let closeMenuBtn = document.querySelector('.close-menu');
let openSidenav = document.querySelector('.sidenav');
let menu = document.querySelector('.menu');
let focusableItems = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', '[tabindex]:not([disabled])', '[contenteditable=true]:not([disabled])'];

//the main function for setting the tabindex to -1 for all children of a parent with given ID (and reversing the process)
function hideOrShowAllInteractiveItems(mainContent){

//build a query string that targets the parent div ID and all children elements that are in our focusable items list.
let queryString = "";
for (i = 0, leni = focusableItems.length; i < leni; i++) {
    queryString += "." + mainContent + " " + focusableItems[i] + ", ";
}
queryString = queryString.replace(/,\s*$/, "");
    
    let focusableElements = document.querySelectorAll(queryString);
    for (j = 0, lenj = focusableElements.length; j < lenj; j++) {

        let el = focusableElements[j];
        if(!el.hasAttribute('data-modified')){ // we use the 'data-modified' attribute to track all items that we have applied a tabindex to (as we can't use tabindex itself).

        // we haven't modified this element so we grab the tabindex if it has one and store it for use later when we want to restore.
            if(el.hasAttribute('tabindex')){
                el.setAttribute('data-oldTabIndex', el.getAttribute('tabindex'));
            }

            el.setAttribute('data-modified', true);
            el.setAttribute('tabindex', '-1'); // add `tabindex="-1"` to all items to remove them from the focus order.

            } 
        else {
            //we have modified this item so we want to revert it back to the original state it was in.
            el.removeAttribute('tabindex');
            if(el.hasAttribute('data-oldtabindex')){
                el.setAttribute('tabindex', el.getAttribute('data-oldtabindex'));
                el.removeAttribute('data-oldtabindex');
            }
            el.removeAttribute('data-modified');
        }
    }
}

let globalLets = {};

function openMenu(){
    menu.classList.add("open");
    openSidenav.classList.add('open-sidenav');
    menuBtn.setAttribute('aria-expanded', true);
    
    //get all the focusable items in our menu and keep track of the button that opened the menu for when we close it again.
    setFocus(menuBtn, 'menu');
    
    content.setAttribute("aria-hidden", true);
}

function closeMenu(){
    //close menu
    //unhide the main content
    content.removeAttribute("aria-hidden");
    //hide the menu
    menu.classList.remove("open");
    openSidenav.classList.remove('open-sidenav');
    // set `aria-expanded` - important for screen reader users.
    menuBtn.setAttribute('aria-expanded', false);
    //set focus back to the button that opened the menu if we can
    if (globalLets.beforeOpen) {
        globalLets.beforeOpen.focus();
    }
}

//toggle the menu
menuBtn.addEventListener('click', function(){
//use our function to add the relevant `tabindex="-1"` to all interactive elements outside of the menu.
hideOrShowAllInteractiveItems('mainContent');
//check if the menu is open, if it is close it and reverse everything.
openMenu();
});

closeMenuBtn.addEventListener('click', function(){
//use our function to add the relevant `tabindex="-1"` to all interactive elements outside of the menu.
hideOrShowAllInteractiveItems('mainContent');
//check if the menu is open, if it is close it and reverse everything.
closeMenu();
});

////// Additional Javascript to close the pop-out menu and revert hidden elements if a user increases the screen width, e.g. by rotating a screen from portrait to landscape, without closing the pop-out menu first.//////

window.addEventListener('resize', wideScreen);
function wideScreen() {
    let ww = window.matchMedia("(min-width: 992px)");
    if (ww.matches) {
        let outer = document.querySelector('.mainContent');
        if (outer.hasAttribute("aria-hidden", true)) { 
        hideOrShowAllInteractiveItems('mainContent');
        closeMenu();
        }
    }
}
//////////////////////////////////TRAPPING FOCUS//////////////////////////////////

let setFocus = function (item, className) { //we pass in the button that activated the menu and the className of the menu list, your menu must have a unique className for this to work.

    className = "sidenav" || "content"; //defaults to class 'content' in case of error ("content" being the class on the <main> element.)
    globalLets.beforeOpen = item; //we store the button that was pressed before the modal opened in a global letiable so we can return focus to it on modal close.

    let findItems = [];
    for (i = 0, len = focusableItems.length; i < len; i++) {
        findItems.push('.' + className + " " + focusableItems[i]); //add every focusable item to an array.
    }
    // finally add the open button to our list of focusable items as it sits outside our menu list. 
    

    let findString = findItems.join(", ");
    globalLets.canFocus = Array.prototype.slice.call(document.querySelectorAll(findString)); 
    if (globalLets.canFocus.length > 0) {
        globalLets.canFocus[0].focus(); //***set the focus to the first focusable element within the modal
        globalLets.lastItem = globalLets.canFocus[globalLets.canFocus.length - 1]; //we also store the last focusable item within the modal so we can keep focus within the modal. 
    }
}

//listen for keypresses and intercept both the Esc key (to close the menu) and tab and shift tab while the menu is open so we can manage focus.
document.onkeydown = function (evt) {
    evt = evt || window.event;
    if (evt.key === "Escape") {
        //unhide the main content - exactly the same as in the btn event listener.
     hideOrShowAllInteractiveItems('mainContent');
     closeMenu();
    }
  if (menu.classList.contains('open') && evt.key == "Tab") { //global letiable to check any modal is open and key is the tab key
        if (evt.shiftKey) { //also pressing shift key
            if (document.activeElement == globalLets.canFocus[0]) { //the current element is the same as the first focusable element
                evt.preventDefault();
                globalLets.lastItem.focus(); //we focus the last focusable element as we are reverse tabbing through the items.
            }
        } else {
        console.log(document.activeElement, globalLets.lastItem);
            if (document.activeElement == globalLets.lastItem) { //when tabbing forward we look for the last tabbable element 
                evt.preventDefault();
                
                globalLets.canFocus[0].focus(); //move the focus to the first tabbable element.
            }
        }
    }
};
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;
}
.menu{
display: none;
}
.menu.open{
  display: block;
}
.sidenav {
  display: none;
  width: 0;
  background-color: #fff;
  box-shadow: 0 2px 5px #acaaaa;
}
.sidenav.open-sidenav {
  display: block;
  position: fixed;
  height: 100%;
  top: 0;
  left: 0;
  width: 150px;
}
<div class="sidenav"><!-- the sidenav is hidden and invisible until the 'open' button is clicked/pressed -->
    <button class="close-menu">Close Menu</button>
    <!-- the close button is inside the sidenav but separate from the menu as the menu is dynamically created -->
    <ul class="menu">
        <li><a href="https://google.com">Google</a></li>
        <li><a href="https://bbc.co.uk">BBC</a></li>
        <li><a href="https://msn.com">MSN</a></li>
    </ul>
</div>
<div class="mainContent">
    <main>
        <p>Some information</p>
        <button class="open-menu">Menu</button><!-- the open button is within the main content -->
        <p>Some more information</p>
        <input />
        <button>a button</button>
    </main>
    <footer>
        <button tabindex="0">a button with a positive tabindex that needs restoring</button>
    </footer>
</div>

于 2021-02-13T12:24:30.120 回答