Базовый обзор того, как создавать адаптивные к цвету, отзывчивые и доступные компоненты FAB.
В этой публикации я хочу поделиться своими мыслями о создании адаптивных к цвету, отзывчивых и доступных компонентов FAB. Попробуйте демо-версию и посмотрите исходный код !
Если вы предпочитаете видео, вот версия этого поста на YouTube:
Обзор
FAB чаще встречаются на мобильных устройствах, чем на настольных компьютерах, но они присутствуют в обоих случаях. Они позволяют держать основные действия на виду, что делает их удобными и вездесущими. Этот стиль пользовательского опыта стал популярным благодаря Material UI, и его рекомендации по использованию и размещению можно найти здесь .
Элементы и стили
HTML-код для этих элементов управления включает элемент-контейнер и набор из одной или нескольких кнопок. Контейнер размещает FAB-кнопки в области просмотра и управляет зазором между кнопками. Кнопки могут быть мини-кнопками или кнопками по умолчанию, что обеспечивает разнообразие основных и дополнительных действий.
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);
}
Затем я присваиваю контейнеру свойство display flex и меняю направление его макета на column-reverse . Это позволяет расположить дочерние элементы друг над другом (в столбце), а также изменить их визуальный порядок. В результате первый фокусируемый элемент становится нижним, а не верхним, как это обычно происходит в HTML-документе. Обратный визуальный порядок объединяет взаимодействие зрячих пользователей и пользователей клавиатуры, поскольку оформление основного действия, большее, чем мини-кнопки, показывает зрячим пользователям, что это основное действие, и пользователи клавиатуры выделят его как первый элемент в исходном коде.

.fabs {
…
display: flex;
flex-direction: column-reverse;
place-items: center;
gap: var(--_viewport-margin);
}
Центрирование выполняется с помощью place-items , а gap добавляет пространство между любыми кнопками FAB, размещенными в контейнере.
FAB-кнопки
Пришло время оформить кнопки так, чтобы они выглядели так, будто парят над всем остальным.
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);
}
Теперь добавим цвет. Мы воспользуемся стратегией, которую уже применяли в GUI Challenges. Создайте набор чётко именованных пользовательских свойств, статически определяющих светлые и тёмные цвета, а затем адаптивное пользовательское свойство, которое будет присвоено переменным «светлый» или «тёмный» в зависимости от системных цветовых предпочтений пользователя:
.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> .
Анимация
Для улучшения пользовательского опыта можно добавлять различные типы анимации. Как и в других задачах GUI, мы настроим несколько пользовательских свойств для реализации идеи ограниченного и полного движения. По умолчанию стили будут предполагать, что пользователь хочет ограниченное движение, а затем с помощью медиазапроса 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