Фокус за пределами видимой области - PullRequest
1 голос
/ 08 мая 2020

WCAG утверждает, что элемент, имеющий фокус, всегда должен быть виден пользователю. Это особенно сложно, если вообще возможно, в окне чата, где пространство ограничено.

Когда пользователь клавиатуры или средства чтения с экрана переходит к первой кнопке и выбирает ее, содержимое прокручивается, и кнопка больше не отображается, нарушая правило WCAG «фокус всегда видимый». Также, если в списке более одной кнопки, фокус остается на кнопке, а если они продолжают переходить на вкладку, окно прокручивается туда, где установлен фокус. Это дезориентирует, и можно утверждать, что при выборе кнопки другие параметры не имеют значения, поскольку теперь доступны новые параметры.

Пример: https://recordit.co/2jDDvqg98J

Один из вариантов - остановить прокрутку при достижении кнопки, чтобы кнопка была видна. Но я считаю, что это плохой опыт и компромисс для соблюдения правила WCAG. Я провел небольшое исследование, и все без исключения диалоговые интерфейсы прокручивают вниз, когда в чате печатается новый контент. Если я отклоняюсь указанным выше способом, чтобы не выходить за рамки WCAG, я нарушаю Закон Якобса.

Другой вариант - удалить фокус с выбранной кнопки на поле ввода или с первой кнопки в следующий / новый список доступных кнопок. Но я чувствую, что это желание слепых пользователей устраняет все точки отсчета.

Есть ли какие-нибудь другие варианты или конструкции, которые вы можете придумать, чтобы решить эту проблему доступным способом?

Ответы [ 2 ]

0 голосов
/ 09 мая 2020

Ваш пример слишком сложен.

Возьмем стандартную HTML страницу: если вы сфокусируете элемент с помощью клавиатуры, вы все равно сможете прокручивать страницу с помощью мыши (без изменения клавиатуры курсор) и убрать элемент из области просмотра. Это не отменяет никаких критериев WCAG.

Нажатие клавиши char на textarea снова сделает его визуально сфокусированным. Для кнопки или ссылки потребуется tab , затем shift tab , чтобы кнопка снова стала видимой и сфокусированной.

Визуальный фокус и фокус клавиатуры - это две разные вещи, но если фокус клавиатуры влияет на визуальный фокус, это не отвечает взаимностью

Проблема, которая может возникнуть у вас, не связана с фокусом, а скорее с проблемой Ограничения по времени .

  1. Не прокручивать, если пользователь не находится в нижней части окна,

  2. Не прокручивать, если действие было выполнено в течение последних N секунд, или подождите P секунд, если никакое другое действие не было выполнено перед прокруткой.

  3. Укажите, что были получены новые сообщения, если windows если не прокрутка.

Я думаю, что в Slack есть хорошая реализация «не прокручивать и указывать новые сообщения» , если вы не внизу.

0 голосов
/ 09 мая 2020

Неполный ответ

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

Фокус вне экрана

Вы зашли в абсолютную букву WCAG и слишком далеко. Смысл этого момента состоит в том, что когда я изменяю фокус, фокусируемый элемент становится видимым на экране.

Если я прокручиваю веб-страницу, вы не можете ожидать, что сфокусированные элементы останутся на странице (в противном случае ни одна страница в мире не была бы совместима, если бы она была длиннее экрана!).

Пока я фокусирую следующий элемент, он прокручивается в поле зрения и имеет индикатор фокуса, который я вижу (правильный контраст, не зависит от цвета) вы имеете рейтинг WCAG AAA по этому пункту!

Автоматическая прокрутка содержимого

Здесь все становится «мутным». В вашем примере контент добавляется в окно чата, и поэтому текущий элемент с фокусом прокручивается с экрана.

Теперь, если мы переместим фокус на последние параметры (появившиеся кнопки), у нас возникнет проблема, которая может прервать поток программы чтения с экрана, и поэтому они не слышат всю предыдущую информацию и должны go вернуться и прослушать снова.

Если мы не переместим фокус, у вас возникнет проблема, которую вы описали, где я нажмите Tab (например), и страница вернется обратно до того, что я только что прослушал.

Если у нас не было других вариантов, это все равно было бы предпочтительнее (без управления фокусом ), но у нас есть варианты.

Пришло время для некоторых обходных путей.

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

Я бы сказал, что самая большая проблема здесь в том, что как только новый текст произносится, мы возвращаемся в верхнюю часть страницы, когда нажимаем Tab или другой фокус rtcuts.

Одним из способов решения этой проблемы было бы создание специального div, который будет фокусироваться, когда я выберу параметр.

Этот div будет иметь tabindex="-1", поэтому он недоступен с клавиатуры ( только программно).

На втором этапе я выбираю параметр, мы фокусируем этот div и затем начинаем вставлять текст.

Таким образом, когда я нажимаю <kbd>Tab</kbd> или ярлык для следующей кнопки, он переходит к первая новая опция.

Я создал элементарную скрипку ниже, она потребует некоторых улучшений, но дает вам шаблон для тестирования / работы. (go полный экран или вы можете не видеть добавленные кнопки et c.)

var hasLoadedMore = 0;
$('.loadMore').on('click', function(e){
    if(hasLoadedMore == 0){ //just a horrible hack to simluate content only loading once when you click an option.
    console.log("option chosen");
    $('#focusAdjuster').attr('aria-hidden', false);
    $('#focusAdjuster').focus();
    console.log("focus adjusted");
    loadContent();
    }
});   



function loadContent(){
    ///ugly way of simulating the content being added dynamically.
    $('#chat').append('<p>additional text</p>');
    $('#chat').append('<p>more text</p>');
    setTimeout(function(){
    $('#chat').append('<p>more text</p>');
    $('#chat').append('<button>Option 1 new</button>');
    $('#chat').append('<button>Option 2 new</button>');
    }, 500);
    hasLoadedMore = 1;
}
.visually-hidden { 
    position: absolute !important;
    height: 1px; 
    width: 1px;
    overflow: hidden;
    clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
    clip: rect(1px, 1px, 1px, 1px);
    white-space: nowrap; /* added line */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chat">
<p>initial text</p>
<button class="loadMore">Option 1</button>
<button class="loadMore">Option 2</button>
<button class="loadMore">Option 3</button>
<div tabindex="-1" aria-hidden="true" id="focusAdjuster" class="visually-hidden">loading</div>
</div>

Объяснение скрипта

Таким образом, ключевыми моментами являются визуально скрытые <div> и сопутствующая строка в JavaScript, которая фокусирует этот div перед загрузкой большего количества контента.

Div позволяет нам изменить фокус после нажатия кнопки. Я также добавил «загрузка» к тексту внутри этого div, чтобы добавить дополнительную цель, так как ваше приложение будет AJAX с питанием.

Div имеет tabindex="-1", поэтому он не может получить фокус. Я также добавил к этому aria-hidden="true" и отключил это при нажатии кнопки выбора, прямо перед тем, как дать ему фокус.

Я бы переключил это обратно, когда фокус покидает этот div в реальном мире, но я не сделать это в быстрой демонстрационной скрипке.

Разве этот WCAG не «проваливает»?

Ага! В этом примере я сделал элемент, на который не фокусируется, фокусируемым, и он не имеет действия. Я все еще думаю, что это предпочтительнее, чем сделать его <button>, поскольку это означает, что у него есть действие. Это явно не идеально.

Однако ключевой частью WCAG является ' G ' - это G uidelines. Я предлагаю «взломать» или пойти на компромисс, основанный на том факте, что я реалист c в отношении времени разработки и технических ограничений.

«Правильный» способ сделать это без div с осторожным управлением фокусом. С неограниченным временем и бюджетом я бы определенно сделал это.

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

Альтернативный шаблон.

Потому что предыдущий пример «терпит неудачу» WCAG, есть еще один вариант, однако я бы сказал, что это хуже и вызывает множество проблем. Обратной стороной является то, что вам нужно будет каждый раз предоставлять кнопки «предыдущий элемент» и отслеживать их, плюс - это будет совместимость с WCAG (хотя я бы сказал, что это не так удобно, даже если вы «проходите» критерии.)

Также предоставление этих кнопок «предыдущий» снова создает ряд проблем с управлением фокусом (когда мы делаем их видимыми, получают ли они cus, они добавляют путаницы?).

Думайте об этом как о шаблоне мастера форм, каждый набор вопросов - это «шаг», поэтому вы можете go вернуться к предыдущим шагам, а вы можете только увидеть текущий шаг на экране.

Я включил это, поскольку этот шаблон можно было бы расширить с некоторой мыслью и чтобы дать OP / другим людям некоторые идеи, НЕ используйте его как есть

var hasLoadedMore = 0;
var optionChosen = "";
$('.loadMore').on('click', function(e){
    if(hasLoadedMore == 0){ //just a horrible hack to simluate content only loading once when you click an option.
    optionChosen = $(this).text();
    console.log("option chosen", optionChosen);
    loadContent();
    }
});   




function loadContent(){
    
    $('#chat').html('<button class="previousQuestion">You chose ' + optionChosen + '<span class="visually-hidden">(click here to go back and chose a different option)</span></button>');
    $('#chat').append('<h3>' + optionChosen + '</h3>');
    ///ugly way of simulating the content being added dynamically.
    $('#chat').append('<p>additional text</p>');
    $('#chat').append('<p>more text</p>');
    setTimeout(function(){
    $('#chat').append('<p>more text</p>');
    $('#chat').append('<button>Option 1 new</button>');
    $('#chat').append('<button>Option 2 new</button>');
    }, 500);
    hasLoadedMore = 1;
    
    
$('.previousQuestion').on('click', function(){
    console.log("now you would restore the previous question");
});   

    
}
.visually-hidden { 
    position: absolute !important;
    height: 1px; 
    width: 1px;
    overflow: hidden;
    clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
    clip: rect(1px, 1px, 1px, 1px);
    white-space: nowrap; /* added line */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="chat">
<p>initial text</p>
<button class="loadMore">Option 1</button>
<button class="loadMore">Option 2</button>
<button class="loadMore">Option 3</button>
<div tabindex="-1" aria-hidden="true" id="focusAdjuster" class="visually-hidden">loading</div>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...