Неполный ответ
Это слишком большой вопрос, чтобы ответить на него полностью, есть сотни вещей, которые нужно учитывать, и с помощью всего лишь 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>