Базовый обзор того, как создавать цветоадаптивные, отзывчивые и доступные компоненты FAB.
В этом посте я хочу поделиться своими мыслями о том, как создавать цветоадаптивные, отзывчивые и доступные компоненты FAB. Попробуйте демо-версию и просмотрите исходный код !
Если вы предпочитаете видео, вот версия этого поста на YouTube:
Обзор
FAB чаще встречаются на мобильных устройствах, чем на настольных компьютерах, но они распространены в обоих сценариях. Они держат в поле зрения основные действия, что делает их удобными и вездесущими. Этот стиль взаимодействия с пользователем стал известен благодаря Material UI, и их предложения по использованию и размещению можно найти здесь .
Элементы и стили
HTML для этих элементов управления включает элемент-контейнер и набор из одной или нескольких кнопок. Контейнер размещает FAB в окне просмотра и управляет зазором между кнопками. Кнопки могут быть мини- или стандартными, что дает хорошее разнообразие между основными и второстепенными действиями.
ФАБ контейнер
Этот элемент может быть обычным <div>
но давайте окажем услугу нашим незамеченным пользователям и пометим его некоторыми полезными атрибутами, чтобы объяснить назначение и содержимое этого контейнера.
FAB-разметка
Начните с класса .fabs
, к которому можно подключить CSS для стиля, затем добавьте role="group"
и aria-label
, чтобы это был не просто общий контейнер, а именованный и целенаправленный.
<div class="fabs" role="group" aria-label="Floating action buttons">
<!-- buttons will go here -->
</div>
стиль FABs
Чтобы FAB было удобно, они всегда остаются в пределах области просмотра. Это отличный вариант использования позиции fixed
. В этой позиции окна просмотра я решил использовать inset-block
и inset-inline
, чтобы эта позиция дополняла режим документа пользователя, например, справа налево или слева направо. Пользовательские свойства также используются для предотвращения повторения и обеспечения равного расстояния от нижнего и боковых краев области просмотра:
.fabs {
--_viewport-margin: 2.5vmin;
position: fixed;
z-index: var(--layer-1);
inset-block: auto var(--_viewport-margin);
inset-inline: auto var(--_viewport-margin);
}
Затем я придаю контейнеру flex
отображения и меняю направление его расположения на column-reverse
. Это складывает дочерние элементы друг на друга (столбец), а также меняет их визуальный порядок на противоположный. В результате первый фокусируемый элемент становится нижним, а не верхним, как обычно в HTML-документе. Изменение визуального порядка на противоположный объединяет опыт зрячих пользователей и пользователей клавиатуры, поскольку стиль основного действия, размер которого больше, чем мини-кнопки, указывает зрячим пользователям, что это основное действие, а пользователи клавиатуры будут фокусировать его как первый элемент в исходном коде. .
.fabs {
…
display: flex;
flex-direction: column-reverse;
place-items: center;
gap: var(--_viewport-margin);
}
Центрирование осуществляется с помощью place-items
, а gap
добавляет пространство между любыми кнопками FAB, помещенными в контейнер.
ПОТРЯСАЮЩИЕ кнопки
Пришло время стилизовать некоторые кнопки так, чтобы они выглядели так, будто они плавают поверх всего.
По умолчанию ФАБ
Первая кнопка, которую нужно стилизовать, — это кнопка по умолчанию. Это послужит основой для всех кнопок FAB. Позже мы создадим вариант, который будет иметь альтернативный внешний вид, изменяя при этом как можно меньше базовых стилей.
FAB-разметка
Элемент <button>
— правильный выбор. Мы начнем с него как с основы, потому что он обеспечивает отличное взаимодействие с мышью, сенсорным экраном и клавиатурой. Самый важный аспект этой разметки — скрыть значок от пользователей программы чтения с экрана с помощью aria-hidden="true"
и добавить необходимый текст метки в саму разметку <button>
. При добавлении меток в этих случаях мне также нравится добавлять title
, чтобы пользователи мыши могли получить информацию о том, что значок надеется сообщить.
<button data-icon="plus" class="fab" title="Add new action" aria-label="Add new action">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>
потрясающий стиль
Сначала давайте превратим кнопку в круглую кнопку с мягкой прокладкой и сильной тенью, поскольку это первые определяющие особенности кнопки:
.fab {
--_size: 2rem;
padding: calc(var(--_size) / 2);
border-radius: var(--radius-round);
aspect-ratio: 1;
box-shadow: var(--shadow-4);
}
Далее добавим цвет. Мы будем использовать стратегию, которую мы использовали раньше в испытаниях с графическим интерфейсом. Создайте четко названный набор пользовательских свойств, которые статически сохраняют светлые и темные цвета, а затем адаптивное пользовательское свойство, которому будут присвоены светлые или темные переменные в зависимости от системных предпочтений пользователя в отношении цветов:
.fab {
…
/* light button and button hover */
--_light-bg: var(--pink-6);
--_light-bg-hover: var(--pink-7);
/* dark button and button hover */
--_dark-bg: var(--pink-4);
--_dark-bg-hover: var(--pink-3);
/* adaptive variables set to light by default */
--_bg: var(--_light-bg);
/* static icon colors set to the adaptive foreground variable */
--_light-fg: white;
--_dark-fg: black;
--_fg: var(--_light-fg);
/* use the adaptive properties on some styles */
background: var(--_bg);
color: var(--_fg);
&:is(:active, :hover, :focus-visible) {
--_bg: var(--_light-bg-hover);
@media (prefers-color-scheme: dark) {
--_bg: var(--_dark-bg-hover);
}
}
/* if users prefers dark, set adaptive props to dark */
@media (prefers-color-scheme: dark) {
--_bg: var(--_dark-bg);
--_fg: var(--_dark-fg);
}
}
Затем добавьте несколько стилей, чтобы значки SVG вписывались в пространство.
.fab {
…
& > svg {
inline-size: var(--_size);
block-size: var(--_size);
stroke-width: 3px;
}
}
Наконец, уберите с кнопки выделение касания, поскольку мы добавили собственную визуальную обратную связь для взаимодействия:
.fab {
-webkit-tap-highlight-color: transparent;
}
Мини ФАБ
Цель этого раздела — создать вариант кнопки FAB. Сделав некоторые из FAB меньше, чем действие по умолчанию, мы можем продвигать действие, которое пользователь выполняет чаще всего.
Мини-разметка FAB
HTML такой же, как FAB, но мы добавляем класс «.mini», чтобы привязать CSS к этому варианту.
<button data-icon="heart" class="fab mini" title="Like action" aria-label="Like action">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>
Мини-стиль FAB
Благодаря использованию пользовательских свойств единственное необходимое изменение — это корректировка переменной --_size
.
.fab.mini {
--_size: 1.25rem;
}
Доступность
Самая важная часть, которую следует помнить для обеспечения доступности с помощью FAB, — это размещение внутри клавиатуры на странице. В этой демоверсии есть только FAB, нет ничего, с чем можно было бы конкурировать с точки зрения порядка и плавности клавиатуры, а это значит, что у нее нет возможности продемонстрировать осмысленную последовательность действий на клавиатуре. В сценарии, где есть конкурирующие элементы за фокус, я предлагаю глубоко подумать о том, в каком месте этого потока пользователь должен оказаться в потоке кнопок FAB.
Как только пользователь сфокусировался на контейнере FAB, мы уже добавили role="group"
и aria-label="floating action buttons"
которые информируют пользователей программ чтения с экрана о содержимом того, на чем они сосредоточились. Стратегически я поместил FAB по умолчанию первым, чтобы пользователи первыми находили основное действие. Затем я использую flex-direction: column-reverse;
чтобы визуально расположить основную кнопку внизу, рядом с пальцами пользователя для облегчения доступа. Это хорошая победа, потому что кнопка по умолчанию визуально заметна, а также является первой для пользователей клавиатуры, что дает им очень похожие впечатления.
Наконец, не забудьте скрыть свои значки от пользователей программ чтения с экрана и убедитесь, что вы предоставили им метку для кнопки, чтобы это не было загадкой. Это уже было сделано в HTML с помощью aria-hidden="true"
для <svg>
и aria-label="Some action"
для <button>
.
Анимация
Для улучшения пользовательского опыта можно добавить различные типы анимации. Как и в других задачах с графическим пользовательским интерфейсом, мы настроим несколько пользовательских свойств, которые будут обеспечивать уменьшенное и полное движение. По умолчанию стили предполагают, что пользователь хочет уменьшить движение, а затем с помощью медиа-запроса prefers-reduced-motion
заменяет значение перехода на полное движение.
Стратегия уменьшенного движения с настраиваемыми свойствами
В следующем CSS создаются три настраиваемых свойства: --_motion-reduced
, --_motion-ok
и --_transition
. Первые две содержат соответствующие переходы с учетом предпочтений пользователя, а последняя переменная --_transition
будет установлена в значение --_motion-reduced
или --_motion-ok
соответственно.
.fab {
/* box-shadow and background-color can safely be transitioned for reduced motion users */
--_motion-reduced:
box-shadow .2s var(--ease-3),
background-color .3s var(--ease-3);
/* add transform and outline-offset for users ok with motion */
--_motion-ok:
var(--_motion-reduced),
transform .2s var(--ease-3),
outline-offset 145ms var(--ease-2);
/* default the transition styles to reduced motion */
--_transition: var(--_motion-reduced);
/* set the transition to our adaptive transition custom property*/
transition: var(--_transition);
/* if motion is ok, update the adaptive prop to the respective transition prop */
@media (prefers-reduced-motion: no-preference) {
--_transition: var(--_motion-ok);
}
}
При наличии вышеизложенного можно перенести изменения в box-shadow
, background-color
, transform
и outline-offset
, давая пользователю приятный отзыв пользовательского интерфейса о том, что его взаимодействие было получено.
Затем добавьте немного больше изящества к состоянию :active
, немного translateY
, это придаст кнопке приятный эффект нажатия:
.fab {
…
&:active {
@media (prefers-reduced-motion: no-preference) {
transform: translateY(2%);
}
}
}
И, наконец, перенесите любые изменения на значки SVG в кнопках:
.fab {
…
&[data-icon="plus"]:hover > svg {
transform: rotateZ(.25turn);
}
& > svg {
@media (prefers-reduced-motion: no-preference) {
will-change: transform;
transition: transform .5s var(--ease-squish-3);
}
}
}
Заключение
Теперь, когда вы знаете, как я это сделал, как бы вы‽ 🙂
Давайте разнообразим наши подходы и изучим все способы разработки в Интернете.
Создайте демо, пришлите мне ссылку в Твиттере , и я добавлю ее в раздел ремиксов сообщества ниже!
Ремиксы сообщества
Здесь пока смотреть нечего.
Ресурсы
- Исходный код на Github