Утром доделаю

Слайдеры и кнопка Tab

Все js-слайдеры подвержены одному смешному багу: они ломаются при использовании кнопки Tab. Если на каком-то слайде есть ссылка, слайдер обязательно сломается при переходе на нее табом. Несколько примеров на слайдере, который не ломается (oh, the irony):

Сломанный слайдер на apple.com
Сломанный слайдер на apple.com
Сломанный слайдер Swipe
Сломанный слайдер Swipe
Сломанный слайдер Стима
Сломанный слайдер Стима

Дело в том, что при фокусировании ссылки, скрытой за overflow: hidden, браузер заботлибо промотает вам содержимое блока, чтобы ссылка оказалась в поле зрения. Да, у блоков с overflow: hidden тоже есть scrollLeft, и он работает так же, как и в случае с overflow: auto.

Решение: ловим событие focus внутри слайдов. Когда событие случается, переключаем слайд на тот, в котором произошло событие, и сбрасываем scrollLeft контейнера слайдов. Событие focus не бабблится, поэтому используем капчуринг, чтобы поймать его на уровне слайдов (почитать про бабблинг и капчуринг). Для старых IE используем фоллбек в виде события focusin, которое бабблится.

Выполняем для каждого слайда:

//Сначала фоллбек для старых IE
slide.onfocusin = function() {
  //Сбрасываем скролл
  _this.scrollLeft = 0;
  //И еще раз с нулевым таймаутом, потому что в вебките скролл выставляется позже события.
  //Первый ресет оставляем, чтобы в других браузерах не дергалось.
  setTimeout(function() {
    _this.scrollLeft = 0;
  }, 0);

  //Переключаем на слайд, к которому привязано событие
  changeActiveSlide(i);
};

//Используем привязанную к `onfocusin` функцию уже в нормальном `addEventListener`
if (slide.addEventListener) slide.addEventListener('focus', slide.onfocusin, true); //`true` включает капчуринг

Можно было бы обойтись событием focusin, но Firefox до сих пор не поддерживает его >:(

«Точки» под слайдером тоже должны дружить с клавиатурой. Чтобы не городить огород, достаточно просто сделать их доступными для табуляции (для этого выставляем им аттрибут tabindex="0") и включать нужный слайд по нажатию энтера.

Естественно, при этом нельзя отключать outline вокруг выделенной точки. Чтобы обводка вокруг точки работала при навигации с клавиатуры, но не мешалась при использовании мыши, существует два приема. Первый — убрать outline для псевдокласса :active, чтобы обводки не было во время нажатой кнопки мыши:

.peppermint.active > ul.dots > li:active {
  outline: none;
}

Второй — снимать фокус после клика мышью:

addEvent(dot, 'click', (function(x, d) {
  return function() {
    d.blur(); //снимаем фокус с точки
    changeActiveSlide(x); //переключаем слайд
    
    ...

  };
})(i, dot), false);

Выше используется простая универсальная функция addEvent:

function addEvent(el, event, func, bool) {
  el.addEventListener? el.addEventListener(event, func, !!bool): el.attachEvent('on'+event, func);
}

Теперь слайдер адекватно работает с клавиатурой и исполняет (вроде бы) необходимый минимум «Руководства по обеспечению доступности веб-контента». Такие дела.

Опубликовано в рубрике «Чиним интернет»