Una descripción general fundamental de cómo compilar componentes de BAF que se adapten al color, sean responsivos y accesibles.
En esta publicación, quiero compartir mis ideas sobre cómo crear componentes de BAF que se adapten al color y sean responsivos y accesibles. Prueba la demostración y mira la fuente.
Si prefieres ver un video, aquí tienes una versión de YouTube de esta publicación:
Descripción general
Los BAF son más comunes en dispositivos móviles que en computadoras de escritorio, pero son frecuentes en ambas situaciones. Mantienen las acciones principales a la vista, por lo que son prácticas y omnipresentes. La IU de Material hizo famoso este estilo de experiencia del usuario, y puedes encontrar aquí tus sugerencias de uso y posición.
Elementos y estilos
El código HTML para estos controles implica un elemento de contenedor y un conjunto de uno o más botones. El contenedor posiciona los BAF dentro del viewport y administra un espacio entre los botones. Los botones pueden ser mini o predeterminados, lo que ofrece una buena variedad entre las acciones principales y secundarias.
Contenedor del BAF
Este elemento puede ser un <div>
normal, pero hagamos un favor a nuestros usuarios ciegos y etiquémoslo con algunos atributos útiles para explicar el propósito y el contenido de este contenedor.
Lenguaje de marcado de los BAF
Comienza con una clase .fabs
para que CSS se vincule con el estilo y, luego, agrega role="group"
y aria-label
para que no sea solo un contenedor genérico, tenga un nombre y un propósito.
<div class="fabs" role="group" aria-label="Floating action buttons">
<!-- buttons will go here -->
</div>
Estilo de los BAF
Para que los BAF sean convenientes, permanecen en el viewport en todo momento.
Este es un excelente caso de uso para la posición fixed
. Dentro de esta posición de viewport, elegí usar inset-block
y inset-inline
para que la posición complemente el modo de documento del usuario, como de derecha a izquierda o de izquierda a derecha. Las propiedades personalizadas también se utilizan para evitar repeticiones y garantizar
la misma distancia desde los bordes inferior y lateral del viewport:
.fabs {
--_viewport-margin: 2.5vmin;
position: fixed;
z-index: var(--layer-1);
inset-block: auto var(--_viewport-margin);
inset-inline: auto var(--_viewport-margin);
}
Luego, le asigno flex
al contenedor flex
y cambio la dirección de diseño a column-reverse
.
Esto apila los elementos secundarios uno sobre otro (columna) y también invierte su orden visual. Esto tiene el efecto de hacer que el primer elemento enfocable sea el elemento inferior en lugar del superior, que sería donde el foco suele ir según el documento HTML. La inversión del orden visual une la experiencia de los usuarios videntes y de teclado, ya que el estilo de la acción principal (más grande que el de los minibotones) indica a los usuarios videntes que es una acción principal, y los usuarios de teclado lo enfocarán como el primer elemento de la fuente.
.fabs {
…
display: flex;
flex-direction: column-reverse;
place-items: center;
gap: var(--_viewport-margin);
}
El centro se controla con place-items
, y gap
agrega espacio entre los botones del BAF que se colocan en el contenedor.
Botones del BAF
Es hora de diseñar algunos botones para que parezca que flotan sobre todo.
BAF predeterminado
El primer botón para aplicar diseño es el predeterminado. Esto servirá de base para todos los botones del BAF. Más adelante, crearemos una variante que logre una apariencia alternativa y, al mismo tiempo, modifique la menor cantidad posible de estos diseños base.
Lenguaje de marcado del BAF
El elemento <button>
es la opción correcta. Comenzaremos con esto como base, ya que ofrece una excelente experiencia del usuario de mouse, panel táctil y teclado. El aspecto más crucial de este lenguaje de marcado es ocultar el ícono de los usuarios de lectores de pantalla con aria-hidden="true"
y agregar el texto de la etiqueta necesario al lenguaje de marcado de <button>
. En estos casos, cuando agregas etiquetas, también me gusta agregar un title
para que los usuarios del mouse puedan obtener información sobre lo que el ícono espera comunicar.
<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>
Estilo de BAF
Primero, convirtamos el botón en un botón redondo con padding con una sombra fuerte, ya que estas son las primeras funciones que definen el botón:
.fab {
--_size: 2rem;
padding: calc(var(--_size) / 2);
border-radius: var(--radius-round);
aspect-ratio: 1;
box-shadow: var(--shadow-4);
}
Ahora, agreguemos color. Usaremos una estrategia que ya usamos en los desafíos de la GUI antes. Crea un conjunto de propiedades personalizadas con un nombre claro que conserve de forma estática los colores claros y oscuros y, luego, una propiedad personalizada adaptable que se establecerá en las variables claro u oscuro según la preferencia del sistema por los colores del usuario:
.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);
}
}
A continuación, agrega algunos estilos para ayudar a que los íconos SVG se ajusten al espacio.
.fab {
…
& > svg {
inline-size: var(--_size);
block-size: var(--_size);
stroke-width: 3px;
}
}
Por último, quita el elemento destacado del botón para presionar, ya que agregamos nuestro propio comentario visual para la interacción:
.fab {
-webkit-tap-highlight-color: transparent;
}
Mini BAF
El objetivo de esta sección es crear una variante para el botón del BAF. Si hacemos algunos BAF más pequeños que la acción predeterminada, podemos promover la acción que el usuario realiza con más frecuencia.
Lenguaje de marcado del mini BAF
El código HTML es el mismo que el BAF, pero agregamos una clase ".mini" para que el CSS tenga un enlace con la variante.
<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>
Estilo mini BAF
Gracias al uso de propiedades personalizadas, el único cambio necesario es realizar un ajuste en
la variable --_size
.
.fab.mini {
--_size: 1.25rem;
}
Accesibilidad
La parte más importante que debes recordar para la accesibilidad con BAF es la ubicación dentro del flujo del teclado de la página. Esta demostración solo tiene los BAF y no hay nada con lo que competir en términos de orden y flujo del teclado, lo que significa que no tiene la oportunidad de demostrar un flujo de teclado significativo. En una situación en la que hay elementos que compiten por el enfoque, te sugerimos que pienses detenidamente en qué parte de ese flujo debería entrar un usuario al flujo del botón del BAF.
Una vez que el usuario se haya enfocado en el contenedor del BAF, ya agregamos role="group"
y aria-label="floating action buttons"
, que informan a los usuarios de lectores de pantalla sobre el contenido en lo que enfocaron. De forma estratégica, coloqué el BAF predeterminado en primer lugar para que los usuarios encuentren primero la acción principal. Luego, uso flex-direction: column-reverse;
para ordenar visualmente el botón principal en la parte inferior, cerca de los dedos del usuario para facilitar el acceso. Esta es una buena opción, ya que el botón predeterminado se destaca visualmente y también está primero para los usuarios de teclado, lo que les brinda experiencias muy similares.
Por último, no olvides ocultar los íconos a los usuarios de lectores de pantalla y asegúrate de proporcionarles una etiqueta para el botón, de modo que no sea un misterio. Esto se hizo en el HTML con aria-hidden="true"
en <svg>
y aria-label="Some action"
en <button>
.
Animación
Se pueden agregar varios tipos de animación para mejorar la experiencia del usuario. Al igual que en otros desafíos de la GUI, configuraremos un par de propiedades personalizadas para conservar el propósito de una experiencia de movimiento reducido y una experiencia de movimiento completa. De forma predeterminada, los diseños supondrán que el usuario desea un movimiento reducido y, luego, con la consulta de medios prefers-reduced-motion
, se cambia el valor de transición a movimiento completo.
Una estrategia de movimiento reducido con propiedades personalizadas
Se crean tres propiedades personalizadas en el siguiente CSS: --_motion-reduced
,
--_motion-ok
y --_transition
. Las dos primeras contienen transiciones adecuadas según la preferencia del usuario, y la última variable --_transition
se establecerá en --_motion-reduced
o --_motion-ok
, respectivamente.
.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);
}
}
Una vez que se implementó lo anterior, se puede realizar la transición de los cambios en box-shadow
, background-color
, transform
y outline-offset
, lo que proporciona al usuario comentarios positivos en la IU que informa que recibió su interacción.
A continuación, agrega un poco más de estilo al estado :active
ajustando un poco translateY
. Esto le dará al botón un buen efecto de presión:
.fab {
…
&:active {
@media (prefers-reduced-motion: no-preference) {
transform: translateY(2%);
}
}
}
Por último, realiza la transición de cualquier cambio a los íconos SVG en los botones:
.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);
}
}
}
Conclusión
Ahora que sabes cómo lo hice, ¿cómo lo harías 🙂
Diversifiquemos nuestros enfoques y aprendamos todas las formas de desarrollar en la Web.
Crea una demostración, twittea vínculos y la agregaré a la sección de remixes de la comunidad a continuación.
Remixes de la comunidad
Aún no hay nada que ver aquí.
Recursos
- Código fuente en GitHub