Привет, front end разработчик! Вы работаете над своими навыками работы с React.js? Ищете проект, в котором используются React Hooks? Если вы хотите научиться создавать доступную React Carousel с несколькими элементами с нуля, доступную, готовую к переводу и инклюзивную, то вы попали по адресу.
Примерное время чтения: 10 минут
Оригинальный пост здесь.
Проект Accessible React Carousel
Идея этой сборки — доступная карусель React, созданная для простого и дружелюбного использования любым пользователем с любого устройства.
Доступная карусель React решает эти специфические проблемы, с которыми сталкиваются различные пользователи:
-
Создание визуального восприятия для зрячих пользователей
-
Создание звукового сопровождения для незрячих или слабовидящих пользователей
-
Создание готового к переводу проекта для зрячих, незрячих или слабовидящих пользователей, не владеющих английским языком.
-
Встроенная анимация для пользователей с вестибулярными или сенсорными нарушениями.
-
Цвет, иконография и маркировка для когнитивной легкости.
Эта доступная карусель на React поставляется с функциями, которые позволяют зрячим и незрячим пользователям пользоваться ею в равной степени. Карусель создана для взаимодействия с людьми, которые согласны взаимодействовать с ней.
Другими словами, людям, имеющим проблемы с органами чувств или равновесием, не придется видеть движение при первой загрузке карусели. Вместо этого они смогут выбирать, хотят они взаимодействовать с каруселью или нет.
Все функции этой карусели готовы к переводу, поэтому любой пользователь, имеющий службу перевода, сможет воспринимать эту карусель визуально или нет.
Ознакомьтесь со сборкой здесь, а увидеть ее в действии можно здесь.
Ключевые концепции
- Управление фокусом и обратная связь — В этом проекте я думал о фокусе клавиатуры и о том, как я могу использовать его для обеспечения обратной связи с пользователями, которые заходят в мою карусель с разных устройств.
? Посмотрите, как я использую фокус, чтобы проинструктировать пользователей о том, что делать.
? Проверьте, как я включаю фокус в обратную связь.
- Согласие — У некоторых пользователей непредвиденное движение может вызвать дискомфорт и возбуждение. Это не идеальная реакция на что-то, что вы создали, так почему бы не предоставить пользователям возможность выбирать, хотят ли они взаимодействовать с движением или нет?
? Посмотрите, как я управляю согласием в элементах управления галереей «Карусель».
Компонент приложения
Основными элементами, которые мы рассмотрим в компоненте App, являются компонент слайдов, инструкции и элементы управления галереей. Как вы можете видеть на изображении ниже, у нас есть
5 слайд-компонентов внутри элемента unordered-list.
Ниже элемента [aria-labelledby=»gallery-label»] находится div инструкции.
Ниже находится div gallery-controls, где мы используем компоненты Buttons.
Состояние и функция компонента App
Компоненты App Components используют useState() React Hook на главном элементе для обработки событий касания мыши для мобильных пользователей. Смысл использования состояния заключается в том, чтобы гарантировать, что наш лендинг компонента инструкции будет работать соответствующим образом на мобильных устройствах, а не только на настольных компьютерах.
Мы определяем использование состояния следующим образом:
const [touched, setTouched] = useState(»);
Мы устанавливаем состояние на главном элементе следующим образом и вызываем функцию onTouchStart:
Далее мы создаем функцию onMainTouchStart, которая будет добавлять имя класса к главному элементу при касании:
const onMainTouchStart = () => {
setTouched('touched');
}`
Styling the touched class
We add the following style which is going to make a lot more sense when we build the instruction component:
`.touched #hover {
display: block!important;
}
Управление фокусом
Для элемента [aria-labelledby=’gallery-label’] мы добавляем атрибут tabIndex, равный 0. Это позволяет пользователю переходить к телу компонента карусели.
Когда клавиатура сфокусирована на этом элементе, инструкции будут печатать другое сообщение, чем если пользователь наведет на него курсор мыши. Это помогает сделать сообщение более четким в зависимости от устройства.
<div role="region" aria-labelledby="gallery-label" tabIndex="0" aria-describedby="focus">`
##Instructions
The instructions div contains a paragraph tags that explain to the user how to interact with the accessible carousel.
##Instruction HTML
`<div className="instructions">
<p id="hover">use buttons or scroll left or right for more</p>
<p id="focus">use buttons, tab, or your left and right arrow keys for more</p>
</div>
CSS для инструкций
Далее нам нужно изменить стиль каждого из этих абзацев, чтобы в зависимости от устройства и действий пользователя отображались только правильные инструкции. Начнем с установки display в none для сообщений hover и focus.
Затем мы включим классы sudo :hover и :focus, а также класс .touched, о котором мы говорили ранее, чтобы он отображался, когда элемент gallery-label наводится мышью, фокусируется клавиатурой или касается сенсорного устройства.
#hover, #focus {
display: none;
text-align: center;
max-width: 50%;
word-break: break-word;
margin: 10px auto;
}
[aria-labelledby="gallery-label"]:hover + .instructions #hover,
[aria-labelledby="gallery-label"]:focus + .instructions #focus,
.touched #hover {
display: block!important;
}
Когда клавиатура фокусируется на элементе [aria-labelledby=»gallery-label»], параграф объясняет пользователю, что нужно использовать кнопки, клавишу табуляции или кнопки со стрелками влево или вправо.
Если пользователь использует мышь или сенсорный экран и фокусируется на этом элементе, параграф объясняет ему, что нужно использовать кнопки или прокрутить страницу влево или вправо.
Это частично ключевая концепция обратной связи, а частично концепция фокусировки. От того, как пользователь обращается к компоненту, будет зависеть тип инструкций, которые он получит.
Компонент слайда
Компонент Slide состоит из элемента списка, рисунка, изображения и связанного с ним figcaption. Идея этого компонента — галерея изображений. Мы можем изменить их на любые другие, например, на карусель постов, но для целей данного урока мы сделаем галерею изображений.
Ниже мы видим элемент списка, рисунок, img, figcaption и т.д., которые составляют компонент Slide:
Согласно документации Unsplash API, галерея должна иметь ссылку на профиль художника. Здесь есть еще несколько обязательных элементов.
Чтобы сделать галерею доступной, изображения должны содержать описание alt. Некоторые художники на Unsplash включают alt-описание, и, используя Unsplash API, вы можете извлечь эту информацию в реквизит.
Элемент галереи также должен содержать:
- url изображения
- имя художника
- должна ли быть выполнена ленивая загрузка изображения.
Мы собираемся использовать встроенную в chrome ленивую загрузку, чтобы ускорить время загрузки нашей карусели. Изображения в начальной закраске не должны быть лениво загружены. Поскольку я спроектировал карусель так, чтобы она по умолчанию показывала первые два изображения, я оставил без внимания атрибуты ленивой загрузки для первых двух компонентов Slide Components.
Реквизиты компонента Slide
Реквизиты компонента Slide следующие;
-
мы передаем реквизит {url} файлу изображения
-
атрибут alt получает реквизит {description}
-
имя исполнителя — реквизит {caption}
-
ссылка на исполнителя — реквизит {user}.
import React from «react»;
const Slide = ({url, description, caption, user, loading}) => {
return (
<li>
<figure>
<img loading={loading} width="700px" src={url} alt={`the photographer's desctipion is ${description}`} />
<figcaption><a href={user} target="_blank" rel="noreferrer" title={`to ${caption} profile`}> By: {caption}</a></figcaption>
</figure>
</li>
);
}
export default Slide;
После того, как слайд был включен в App Component и мы определили эти реквизиты из Unsplash API, мы получаем элемент списка, который выглядит примерно так:
Gallery Controls
Мы создаем элементы управления галереей с помощью двух элементов списка, содержащих кнопки переключения. Эти кнопки прокручивают карусель для пользователя. Возможно, вы уже заметили, что эта карусель не прокручивается автоматически. Это сделано намеренно.
Управление согласием
Быстрый темп движения может вызывать физическую боль и дискомфорт у некоторых пользователей. Предоставление пользователям полного контроля над перемещением галереи, когда они этого хотят, является более инклюзивным способом проектирования подобных элементов.
Включение компонентов кнопок
Ознакомьтесь с моим постом о доступных кнопках-переключателях здесь, чтобы узнать, как создать эти компоненты многократного использования. Я взял эти кнопки и поместил их в один файл App Component.
Реквизиты компонента «Кнопки
Если вы ознакомились с этим руководством, вы могли заметить, что я изменил способ работы реквизитов в компонентах Buttons в этом проекте.
Компоненту Buttons нужны следующие реквизиты:
- {label} для текста кнопки и classname,
- {fontIcon} для соответствующего значка Font Awesome,
- {ariaButton} для управления состоянием атрибута aria-pressed, и
- {onEvent} для создания уникальной обработки событий при использовании кнопки.
Включите компонент Button в тот же файл, что и компонент App:
const Buttons = ({label, fontIcon, ariaButton, onEvent}) => {
return (
<div className="button-section">
<button onClick={onEvent} className={label} aria-pressed={ariaButton} type="button">{fontIcon}{label}{fontIcon}</button>
</div>
);
}
Я понял, что мне нужны предыдущая и следующая кнопки для выполнения разных задач. Предыдущая кнопка должна была прокручивать страницу влево, а следующая — вправо. Я также смог рефакторить эти кнопки, чтобы реквизит fontIcon мог вызывать иконку, необходимую для кнопки (т. е. для предыдущей кнопки — иконку faIconPrev).
Использование состояния для компонентов кнопок
Мы определяем состояние для атрибута aria-pressed, чтобы управлять функциями и стилем нашей кнопки.
Состояния faIconNext и faIconPrev определяют значок Font Awesome, который мы будем использовать для кнопки.
//button hooks
const [ariaPressed, setAriaPressed] = useState(false);
const [faIconNext, setFaIconNext] = useState(<FontAwesomeIcon icon={faForward} />);
const [faIconPrev, setFaIconPrev] = useState(<FontAwesomeIcon icon={faBackward} />);
Использование функций прокрутки с помощью крючка UseRef
В компоненте App определите galleryRef:
const galleryRef = useRef();
Back on the aria-labelledby="gallery-label" element, we utilize this ref:
<div ref={galleryRef} role="region" aria-labelledby="gallery-label" tabIndex="0" aria-describedby="focus">
Функции прокрутки
Внутри компонента App я создаю функции scrollNext и scrollPrev для прокрутки влево или вправо соответственно, используя элемент galleryRef:
const scrollNext = () => {
galleryRef.current.scrollBy({
top: 0,
left: 625,
behavior: 'smooth'
});
}
const scrollPrev = () => {
galleryRef.current.scrollBy({
top: 0,
left: -585,
behavior: 'smooth'
});
}
События кнопки OnClick
Мы определяем свойство onEvent для каждой кнопки из компонента Buttons:
<li>
<Buttons ariaButton={ariaPressed} onEvent={onButtonPrevClick} fontIcon={faIconPrev} label="previous" />
</li>
<li>
<Buttons ariaButton={ariaPressed} onEvent={onButtonNextClick} fontIcon={faIconNext} label="next" />
</li>
Next inside the onButtonNextClick and onButtonPrevClick functions we’ll call the scrollNext or scrollPrev functions respectively, and set the state for the font icon.
//next click
const onButtonNextClick = () => {
scrollNext();
if (ariaPressed === false){
setAriaPressed(true);
setFaIconNext(<FontAwesomeIcon icon={faThumbsUp} />);
setTimeout(() => {
setAriaPressed(false);
setFaIconNext(<FontAwesomeIcon icon={faForward} />);
}, 600);
console.log("button clicked");
} else {
setAriaPressed(false);
setFaIconNext(<FontAwesomeIcon icon={faForward} />);
}
}
//prev click
const onButtonPrevClick = () => {
scrollPrev();
if (ariaPressed === false){
setAriaPressed(true);
setFaIconPrev(<FontAwesomeIcon icon={faThumbsUp} />);
setTimeout(() => {
setAriaPressed(false);
setFaIconPrev(<FontAwesomeIcon icon={faBackward} />);
}, 600);
console.log("button clicked");
} else {
setAriaPressed(false);
setFaIconPrev(<FontAwesomeIcon icon={faBackward} />);
}
}
В итоге мы получаем согласованное и точное поведение кнопок для каждой из наших кнопок.
Заключение
Надеюсь, теперь у вас есть основные строительные блоки, необходимые для создания любого вида доступной карусели с помощью React.js.
Более широкая аудитория пользователей сможет использовать и наслаждаться вашей доступной каруселью React.
Некоторые ключевые понятия были рассмотрены в курсе, как создать визуальную обратную связь в зависимости от устройства и текущего использования. Мы использовали цвет, иконографию и маркировку для облегчения когнитивной нагрузки для зрячих пользователей. Мы расширили нашу аудиторию, включив маркировку для незрячих пользователей, которые могут не знать английского языка. А включив в сборку управление фокусом и согласие, наша доступная React Carousel стала инклюзивной для всех типов пользователей.
Фото Serge Kutuzov on Unsplash
Ищете другие проекты на React? Посмотрите, как сделать доступный список дел и как создать доступные кнопки переключения.