Creazione di un componente Pulsante di azione floating (FAB)

Una panoramica di base su come creare componenti FAB adattabili al colore, reattivi e accessibili.

In questo post voglio condividere le mie idee su come creare componenti FAB adattabili al colore, reattivi e accessibili. Prova la demo e visualizza il codice sorgente.

Se preferisci i video, ecco una versione di questo post su YouTube:

Panoramica

I FAB sono più comuni sui dispositivi mobili che sui computer, ma sono prevalenti in entrambi gli scenari. Mantengono in vista le azioni principali, rendendole comode e onnipresenti. Questo stile di esperienza utente è stato reso famoso da Material UI e i relativi suggerimenti per l'utilizzo e il posizionamento sono disponibili qui.

Elementi e stili

Il codice HTML di questi controlli include un elemento contenitore e un insieme di uno o più pulsanti. Il contenitore posiziona i pulsanti di azione rapida all'interno dell'area visibile e gestisce uno spazio tra i pulsanti. I pulsanti possono essere piccoli o predefiniti, offrendo una buona varietà tra azioni principali e secondarie.

Contenitore FAB

Questo elemento può essere un normale <div>, ma facciamo un favore ai nostri utenti non vedenti e tagghiamolo con alcuni attributi utili per spiegare lo scopo e i contenuti di questo contenitore.

Markup dei FAB

Inizia con una classe .fabs per CSS a cui collegarti per lo stile, poi aggiungi role="group" e aria-label in modo che non sia solo un contenitore generico, ma denominato e mirato.

<div class="fabs" role="group" aria-label="Floating action buttons">
  <!-- buttons will go here -->
</div>

Stile dei FAB

Per essere pratici, i FAB rimangono sempre all'interno dell'area visibile. Questo è un ottimo caso d'uso per la posizione fixed. All'interno di questa posizione della finestra ho scelto di utilizzare inset-block e inset-inline in modo che la posizione si adatti alla modalità del documento dell'utente, ad esempio da destra a sinistra o da sinistra a destra. Le proprietà personalizzate vengono utilizzate anche per evitare ripetizioni e garantire una distanza uguale dai bordi inferiore e laterali della finestra.

.fabs {
  --_viewport-margin: 2.5vmin;

  position: fixed;
  z-index: var(--layer-1);

  inset-block: auto var(--_viewport-margin);
  inset-inline: auto var(--_viewport-margin);
}

Successivamente, assegno al contenitore la visualizzazione flex e modifico la direzione del layout in column-reverse. In questo modo i figli vengono impilati uno sopra l'altro (colonna) e viene invertito anche il loro ordine visivo. In questo modo, il primo elemento attivabile diventa l'elemento in basso anziché quello in alto, che è la posizione in cui viene normalmente impostato lo stato attivo in base al documento HTML. L'inversione dell'ordine visivo unisce l'esperienza per gli utenti vedenti e per gli utenti che utilizzano la tastiera, in quanto lo stile dell'azione principale più grande dei mini pulsanti indica agli utenti vedenti che si tratta di un'azione principale, mentre gli utenti che utilizzano la tastiera la selezioneranno come primo elemento della sorgente.

Vengono mostrati due pulsanti di azione rapida con DevTools che si sovrappone al layout a griglia. Mostra lo spazio tra loro con un motivo a strisce e anche l&#39;altezza e la larghezza calcolate.

.fabs {
  

  display: flex;
  flex-direction: column-reverse;
  place-items: center;
  gap: var(--_viewport-margin);
}

La centratura viene gestita con place-items e gap aggiunge spazio tra i pulsanti FAB posizionati nel contenitore.

Pulsanti FAB

È il momento di dare uno stile ai pulsanti in modo che sembrino fluttuare sopra ogni cosa.

FAB predefinito

Il primo pulsante da formattare è quello predefinito. che fungerà da base per tutti i pulsanti di azione rapida. In seguito creeremo una variante che ottenga un aspetto alternativo modificando il meno possibile questi stili di base.

Markup FAB

L'elemento <button> è la scelta giusta. Inizieremo con questa base perché offre un'ottima esperienza utente con mouse, tocco e tastiera. L'aspetto più cruciale di questo markup è nascondere l'icona agli utenti di screen reader con aria-hidden="true" e aggiungere il testo dell'etichetta necessario al markup <button> stesso. Quando aggiungo etichette in questi casi, mi piace anche aggiungere un title in modo che gli utenti che utilizzano il mouse possano ottenere informazioni su ciò che l'icona vuole comunicare.

<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>

Stile FAB

Innanzitutto, trasformiamo il pulsante in un pulsante rotondo imbottito con un'ombra marcata, in quanto si tratta delle prime caratteristiche che definiscono il pulsante:

.fab {
  --_size: 2rem;

  padding: calc(var(--_size) / 2);
  border-radius: var(--radius-round);
  aspect-ratio: 1;
  box-shadow: var(--shadow-4);
}

A questo punto, aggiungiamo il colore. Utilizzeremo una strategia che abbiamo già utilizzato in precedenza nelle sfide GUI. Crea un insieme di proprietà personalizzate con un nome chiaro che contengano staticamente i colori chiari e scuri, poi una proprietà personalizzata adattiva che verrà impostata sulle variabili chiare o scure a seconda della preferenza di sistema dell'utente per i colori:

.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);
  }
}

Poi aggiungi alcuni stili per adattare le icone SVG allo spazio.

.fab {
  

  & > svg {
    inline-size: var(--_size);
    block-size: var(--_size);
    stroke-width: 3px;
  }
}

Infine, rimuovi l'evidenziazione del tocco dal pulsante, poiché abbiamo aggiunto un feedback visivo per l'interazione:

.fab {
  -webkit-tap-highlight-color: transparent;
}

Mini FAB

L'obiettivo di questa sezione è creare una variante per il pulsante Azione rapida. Rendendo alcuni FAB più piccoli dell'azione predefinita, possiamo promuovere l'azione che l'utente esegue più spesso.

Markup mini FAB

Il codice HTML è lo stesso di un FAB, ma aggiungiamo una classe ".mini" per fornire al CSS un hook nella 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>
Stile mini FAB

Grazie all'utilizzo delle proprietà personalizzate, l'unica modifica necessaria è un aggiustamento della variabile --_size.

.fab.mini {
  --_size: 1.25rem;
}

Screenshot dei due pulsanti di azione rapida impilati, con il pulsante in alto più piccolo di quello in basso.

Accessibilità

La parte più importante da ricordare per l'accessibilità con i FAB è il posizionamento all'interno del flusso della tastiera della pagina. Questa demo contiene solo i pulsanti di azione rapida, quindi non c'è nulla con cui competere in termini di ordine e flusso della tastiera, il che significa che non ha l'opportunità di dimostrare un flusso della tastiera significativo. In uno scenario in cui sono presenti elementi in competizione per la messa a fuoco, ti suggerisco di riflettere attentamente su quale punto del flusso un utente dovrebbe trovarsi per entrare nel flusso del pulsante FAB.

Dimostrazione dell'interazione con la tastiera

Una volta che l'utente ha messo a fuoco il contenitore del FAB, abbiamo già aggiunto role="group" e aria-label="floating action buttons", che informano gli utenti di screen reader sui contenuti su cui hanno messo a fuoco. A livello strategico, ho posizionato per prima la FAB predefinita, in modo che gli utenti trovino prima l'azione principale. Poi utilizzo flex-direction: column-reverse; per ordinare visivamente il pulsante principale in basso, vicino alle dita degli utenti per un facile accesso. Si tratta di un ottimo risultato perché il pulsante predefinito è visivamente prominente ed è anche il primo per gli utenti della tastiera, offrendo loro esperienze molto simili.

Infine, non dimenticare di nascondere le icone agli utenti di screen reader e assicurati di fornire loro un'etichetta per il pulsante in modo che non sia un mistero. Questa operazione è già stata eseguita nel codice HTML con aria-hidden="true" su <svg> e aria-label="Some action" su <button>.

Animazione

Per migliorare l'esperienza utente, è possibile aggiungere vari tipi di animazione. Come in altre sfide della GUI, configureremo un paio di proprietà personalizzate per contenere l'intento di un'esperienza di movimento ridotto e un'esperienza di movimento completo. Per impostazione predefinita, gli stili presuppongono che l'utente voglia un movimento ridotto, quindi, utilizzando la query multimediale prefers-reduced-motion, scambiano il valore di transizione con il movimento completo.

Una strategia di movimento ridotto con proprietà personalizzate

Nel seguente CSS vengono create tre proprietà personalizzate: --_motion-reduced, --_motion-ok e --_transition. Le prime due contengono le transizioni appropriate in base alle preferenze dell'utente, mentre l'ultima variabile --_transition verrà impostata su --_motion-reduced o --_motion-ok rispettivamente.

.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);
  }
}

Con le modifiche sopra descritte, è possibile eseguire la transizione delle modifiche a box-shadow, background-color, transform e outline-offset, fornendo all'utente un feedback dell'interfaccia utente che indica che la sua interazione è stata ricevuta.

Poi, aggiungi un po' di stile allo stato :active regolando translateYleggermente, in modo da dare al pulsante un bell'effetto di pressione:

.fab {
  

  &:active {
    @media (prefers-reduced-motion: no-preference) {
      transform: translateY(2%);
    }
  }
}

Infine, esegui la transizione di tutte le modifiche alle icone SVG nei pulsanti:

.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);
    }
  }
}

Conclusione

Ora che sai come ho fatto, come faresti tu?‽ 🙂

Diversifichiamo i nostri approcci e impariamo tutti i modi per creare sul web.

Crea una demo, inviami un tweet con i link e la aggiungerò alla sezione dei remix della community qui sotto.

Remix della community

Ancora nessun elemento da visualizzare.

Risorse