Как предотвратить фокусировку программы чтения с экрана (не относящуюся к фокусу клавиатуры) из предопределенной области (например, модальной) - PullRequest
0 голосов
/ 17 октября 2019

Я пытался выяснить, как удерживать фокус чтения с экрана в определенной области. Когда я говорю о фокусировке программы чтения с экрана, я не имею в виду фокус браузера по умолчанию, который можно перемещать с помощью табуляции / сдвига. Я преимущественно реализую специальные возможности при использовании Voiceover на Mac, и когда вы включаете его, на странице появляется новое поле фокусировки и считывается информация, которую он «выделяет».

В этот момент, если вы хотитеНа вкладке браузер и фокус чтения с экрана перемещаются одновременно. Помимо вкладок к различным фокусируемым элементам, вы также можете удерживать cmd + opt и нажатие клавиш влево и вправо для перемещения фокуса программы чтения с экрана от элемента к элементу, независимо от того, можно ли на него перейти. Это фокус, который я пытаюсь сдержать.

Я пытался предотвратить нажатие клавиш cmd, opt и arrow, когда фокус находится на последнем элементе, который я хочу сфокусировать, но браузер этого не делаеткажется, распознают фокус чтения с экрана. И я считаю, что отключение клавиатуры в любом случае не будет работать с программой чтения с экрана, так как, похоже, она работает независимо от браузера.

Я также пытался динамически добавлять tabindex: -1 и aria-hidden: trueко всем другим элементам на странице, когда появляется модальное. Это работает, когда вы включаете Voiceover после факта;фокус чтения с экрана действительно оказывается в ловушке. Однако, если программа чтения с экрана включена, что, скорее всего, будет иметь место в большинстве случаев, программа чтения с экрана не учитывает динамические изменения. Как будто программа чтения с экрана делает «снимок» состояния доступности при загрузке страницы и не учитывает новые изменения в DOM.

У кого-нибудь есть идеи?

Ответы [ 2 ]

1 голос
/ 17 октября 2019

Вы не можете запретить использование сочетаний клавиш программы чтения с экрана. Они имеют приоритет над всем остальным. Они даже не попадают в обработчик нажатия клавиш / вверх / нажатия в вашем скрипте. К счастью для нас как пользователей программ чтения с экрана, это неприемлемый путь.

Как вы также заметили, курсор обзора практически полностью независим от системного фокуса. Дерево доступности определяет, чего можно достичь при использовании курсора просмотра программы чтения с экрана.

Чтобы временно ограничить элементы, видимые курсором обзора, необходимо использовать атрибут aria-modal. Поместите это в корневой элемент, который должен быть достижимым. Все внутри останется достижимым. Все остальное снаружи больше не будет доступно, пока атрибут остается на элементе.

Не играйте с aria-hidden, чтобы получить тот же эффект. Некоторые программы чтения с экрана имеют проблемы с вложенными элементами, имеющими скрытый атрибут aria. Например, если внешний элемент имеет aria-hidden = true, а внутренний элемент имеет aria-hidden = false, Jaws не будет отображать внутренний элемент.

Ограничение курсора обзора также с помощью aria-modalкак, к слову, скрытие элементов с помощью aria-hidden, автоматически не подразумевает, что они не могут быть сфокусированы с обычным фокусом системы (Tab / Shift + Tab). Поэтому вы обычно удваиваете арио-модальное ограничение с ловушкой фокуса, чтобы предотвратить попадание фокуса системы туда, где это не ожидается. Если вы этого не сделаете, вы можете создать проблемы для пользователей программы чтения с экрана (что должна делать программа чтения с экрана, если в данный момент фокус находится на элементе, скрытом от дерева доступности?). Это периодический недосмотр.

Самый безопасный способ сделать фокус-ловушку - это поймать вкладку на последнем разрешенном элементе и shift + tab на первом, и соответственно. вернуть фокус на первый или последний разрешенный элемент. Это гораздо проще, чем установить для всех фокусируемых элементов значение tabindex = -1, а затем вернуться к tabindex = 0, и, как я уже проверял, это работает почти везде.

0 голосов
/ 18 октября 2019

Вот метод, который я использую для управления фокусом для модалов, который решает проблему, с которой вы сталкиваетесь.

Переменная 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();
}

Это хорошо работает для нашего варианта использования, и хотя это может быть сделано с приборкой, и мы имеемнесколько странных практик (глобальные переменные ... у нас есть веские причины, я обещаю!), надеюсь, они вам пригодятся.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...