Isotope — это мощная библиотека для динамической фильтрации и сортировки элементов на веб-странице, однако при работе с доступностью возникает ряд особенностей, связанных с поддержкой пользователей, использующих скринридеры. Скринридеры не воспринимают визуальные анимации и скрытые элементы так же, как обычные пользователи, поэтому важно корректно интегрировать ARIA-атрибуты и семантическую разметку.
Для элементов, фильтруемых с помощью Isotope, необходимо определить семантические роли. Основные рекомендации:
role="list" — контейнер элементов,
которые будут сортироваться или фильтроваться.role="listitem" — каждый отдельный
элемент списка. Это позволяет скринридерам воспринимать изменения в
структуре списка корректно.aria-hidden="true" — применяется к
элементам, которые временно скрыты через Isotope, чтобы скринридеры
игнорировали их.aria-live="polite" — контейнеру, в
котором динамически изменяется содержимое, чтобы озвучивать пользователю
изменения без резкого прерывания текущего потока речи.Пример базовой структуры с ARIA-атрибутами:
<div id="grid" role="list" aria-live="polite">
<div class="grid-item" role="listitem">Элемент 1</div>
<div class="grid-item" role="listitem">Элемент 2</div>
<div class="grid-item" role="listitem">Элемент 3</div>
</div>
Isotope использует CSS-свойства для фильтрации элементов
(display: none, position: absolute и т.д.),
что не всегда корректно воспринимается скринридерами. Рекомендуется:
aria-hidden="true" для
элементов, скрываемых Isotope.aria-hidden, чтобы скринридер мог озвучить
элемент.Пример обновления атрибутов через JavaScript при фильтрации:
var iso = new Isotope('#grid', {
itemSelector: '.grid-item',
layoutMode: 'fitRows'
});
function filterItems(filter) {
iso.arrange({ filter: filter });
document.querySelectorAll('.grid-item').forEach(function(item) {
if (item.matches(filter)) {
item.removeAttribute('aria-hidden');
} else {
item.setAttribute('aria-hidden', 'true');
}
});
}
Скринридеры ориентируются на текущий фокус в документе. При фильтрации важно учитывать:
focus() или
tabindex="0" для корректной
навигации.Пример переноса фокуса на первый видимый элемент после фильтрации:
iso.on('arrangeComplete', function() {
var firstVisible = document.querySelector('.grid-item:not([aria-hidden="true"])');
if (firstVisible) {
firstVisible.setAttribute('tabindex', '-1');
firstVisible.focus();
}
});
Для пользователей скринридеров полезно предоставлять краткие уведомления о количестве элементов, оставшихся после фильтрации:
<div id="filter-status" aria-live="polite"></div>
iso.on('arrangeComplete', function(filteredItems) {
var status = document.getElementById('filter-status');
status.textContent = filteredItems.length + ' элементов отображается';
});
Использование aria-live="polite"
обеспечивает озвучивание изменений без прерывания текущего чтения
контента.
Enter,
Space, Arrow).Эти подходы обеспечивают совместимость Isotope с технологиями экранного доступа, позволяя динамическим сеткам и спискам оставаться доступными для всех пользователей.