Вот метод, который я использую для управления фокусом для модалов, который решает проблему, с которой вы сталкиваетесь.
Переменная item
- это ссылка на кнопку, которая была нажата перед открытием модального окна (поэтому мы можем вернуть фокуспосле закрытия модального окна).
Переменная className
является именем класса модального окна, поэтому вы можете использовать разные модальные объекты.
kluio.helpers
- это просто массив функций, которые я использую на сайте, поэтому его можно опустить.
kluio.globalVars
- это массив глобальных переменных, поэтому его можно заменить на возвращение результатов изфункция.
Я добавил комментарии к каждой части, чтобы объяснить, что она делает.
Функция setFocus
вызывается, когда модальное окно открывается, передавая элемент, который был нажат, чтобы активировать его, иclassName модала (лучше подходит для нашего варианта использования, вместо него следует использовать идентификатор).
var kluio = {};
kluio.helpers = {};
kluio.globalVars = {};
kluio.helpers.setFocus = function (item, className) {
className = className || "content"; //defaults to class 'content' in case of error (content being the <main> element.
kluio.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 focusableItems = ['a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'button:not([disabled])', '[tabindex="0"]']; //a list of items that should be focusable.
var findItems = [];
for (i = 0, len = focusableItems.length; i < len; i++) {
findItems.push('.' + className + " " + focusableItems[i]); //add every focusable item to an array.
}
var findString = findItems.join(", ");
kluio.globalVars.canFocus = Array.prototype.slice.call($('body').find(findString)); //please note we use a custom replacement for jQuery, pretty sure .find() behaves identically but just check it yourself.
if (kluio.globalVars.canFocus.length > 0) {
setTimeout(function () { //set timeout not needed most of the time, we have a modal that is off-screen and slides in, setting focus too early results in the page jumping so we added a delay.
kluio.globalVars.canFocus[0].focus(); //set the focus to the first focusable element within the modal
kluio.globalVars.lastItem = kluio.globalVars.canFocus[kluio.globalVars.canFocus.length - 1]; //we also store the last focusable item within the modal so we can keep focus within the modal.
}, 600);
}
}
Затем мы перехватываем событие keydown
с помощью следующей функции для управления фокусом.
document.onkeydown = function (evt) {
evt = evt || window.event;
if (evt.keyCode == 27) {
closeAllModals(); //a function that will close any open modal with the Escape key
}
if (kluio.globalVars.modalOpen && 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 == kluio.globalVars.canFocus[0]) { //the current element is the same as the first focusable element
evt.preventDefault();
kluio.globalVars.lastItem.focus(); //we focus the last focusable element as we are reverse tabbing through the items.
}
} else {
if (document.activeElement == kluio.globalVars.lastItem) { //when tabbing forward we look for the last tabbable element
evt.preventDefault();
kluio.globalVars.canFocus[0].focus(); //move the focus to the first tabbable element.
}
}
}
};
Наконец, в вашей версии функции closeAllModals
вам нужно вернуть фокус на ссылающийся элемент.
if (kluio.globalVars.beforeOpen) {
kluio.globalVars.beforeOpen.focus();
}
Это хорошо работает для нашего варианта использования, и хотя это может быть сделано с приборкой, и мы имеемнесколько странных практик (глобальные переменные ... у нас есть веские причины, я обещаю!), надеюсь, они вам пригодятся.