Una panoramica di base su come creare componenti FAB adattabili al colore, reattivi e accessibili.
In questo post voglio condividere le mie opinioni su come creare componenti FAB adattabili, 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 visibili le azioni principali, rendendole comode e omnipresenti. Questo stile di esperienza utente è stato reso famoso da Material UI e i suoi suggerimenti per l'utilizzo e il posizionamento sono disponibili qui.
Elementi e stili
Il codice HTML di questi controlli prevede un elemento contenitore e un insieme di uno o più pulsanti. Il contenitore posiziona i FAB all'interno dell'area visibile e gestisce un spazio tra i pulsanti. I pulsanti possono essere mini o predefiniti, con una buona varietà tra le azioni principali e secondarie.
Contenitore FAB
Questo elemento può essere un normale <div>
, ma facciamo un favore ai nostri utenti non vedenti e etichettiamolo con alcuni attributi utili per spiegare lo scopo e i contenuti di questo contenitore.
Markup delle FAB
Inizia con una classe .fabs
a cui il CSS può collegarsi per lo stile, quindi aggiungi role="group"
e aria-label
in modo che non sia solo un contenitore generico, ma sia nominato e utile.
<div class="fabs" role="group" aria-label="Floating action buttons">
<!-- buttons will go here -->
</div>
Stile delle FAB
Per comodità, i FAB rimangono sempre all'interno dell'area visibile.
Questo è un ottimo caso d'uso per la posizione
fixed
. All'interno di questa posizione dell'area visibile ho scelto di utilizzare inset-block
e inset-inline
, in modo che la posizione si adatti alla modalità documento dell'utente, ad esempio da destra a sinistra o da sinistra a destra. Le proprietà personalizzate vengono utilizzate anche per evitare le ripetizioni e garantire la stessa distanza dai bordi inferiore e laterale dell'area visibile:
.fabs {
--_viewport-margin: 2.5vmin;
position: fixed;
z-index: var(--layer-1);
inset-block: auto var(--_viewport-margin);
inset-inline: auto var(--_viewport-margin);
}
Poi associo al contenitore il display
flex
e ne modifico la
direzione del layout in
column-reverse
.
In questo modo, gli elementi secondari vengono impilati uno sopra l'altro (colonna) e anche il loro ordine visivo viene invertito. Questo ha l'effetto di rendere il primo elemento attivabile l'elemento inferiore anziché quello superiore, che è dove lo stato attivo viene normalmente impostato nel documento HTML. L'inversione dell'ordine visivo unisce l'esperienza per gli utenti vedenti e quelli che usano la tastiera, poiché lo stile dell'azione principale più grande rispetto ai mini pulsanti indica agli utenti vedenti che si tratta di un'azione principale e gli utenti che usano la tastiera la metteranno a fuoco come primo elemento nell'origine.
.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 qualsiasi pulsante FAB posizionato nel contenitore.
Pulsanti FAB
È il momento di applicare uno stile ad alcuni pulsanti in modo che risultino fluttuanti sopra ogni cosa.
FAB predefinito
Il primo pulsante da applicare è il pulsante predefinito. che fungerà da base per tutti i pulsanti FAB. In seguito, creeremo una variante che raggiunge un aspetto alternativo modificando il minor numero possibile di 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 ed esperienza della tastiera. L'aspetto più fondamentale 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 aggiungi etichette in questi casi, mi piace anche aggiungere un title
in modo che gli utenti che usano 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
Per prima cosa, trasformiamo il pulsante in un pulsante arrotondato con bordi rialzati e un'ombra marcata, poiché si tratta delle prime caratteristiche che lo definiscono:
.fab {
--_size: 2rem;
padding: calc(var(--_size) / 2);
border-radius: var(--radius-round);
aspect-ratio: 1;
box-shadow: var(--shadow-4);
}
Aggiungiamo il colore. Utilizzeremo una strategia già utilizzata in precedenza nelle sfide GUI. Crea un insieme di proprietà personalizzate denominate in modo chiaro che contengono in modo statico i colori chiari e scuri, quindi 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);
}
}
Successivamente, 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 il nostro feedback visivo per l'interazione:
.fab {
-webkit-tap-highlight-color: transparent;
}
Mini FAB
Lo scopo di questa sezione è creare una variante per il pulsante FAB. Rendendo alcuni FAB più piccoli rispetto all'azione predefinita, possiamo promuovere l'azione più spesso eseguita dall'utente.
Markup Mini FAB
L'HTML è uguale al FAB, ma aggiungiamo una classe ".mini" per assegnare 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 FAB mini
Grazie all'utilizzo delle proprietà personalizzate, l'unica modifica necessaria è un aggiustamento della variabile --_size
.
.fab.mini {
--_size: 1.25rem;
}
Accessibilità
L'aspetto più importante da ricordare per l'accessibilità con i FAB è il posizionamento all'interno del flusso della tastiera della pagina. Questa demo ha solo i FAB, non c'è concorrenza 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 ci sono elementi concorrenti per l'attenzione, suggerisco di pensare attentamente a dove un utente dovrebbe trovarsi in questo flusso nel flusso del pulsante FAB.
Una volta che l'utente ha attivato il contenitore FAB, abbiamo già aggiunto role="group"
e aria-label="floating action buttons"
per informare gli utenti dello screen reader sui contenuti su cui hanno attivato la funzionalità. Per motivi strategici, ho collocato prima il FAB predefinito, in modo che gli utenti trovino prima l'azione principale. Poi uso flex-direction: column-reverse;
per disporre visivamente il pulsante principale in basso, vicino alle dita dell'utente per un facile accesso. Si tratta di un risultato positivo
perché il pulsante predefinito è in evidenza e viene visualizzato per primo per gli utenti
con tastiera, offrendo loro esperienze molto simili.
Infine, non dimenticare di nascondere le icone agli utenti che utilizzano screen reader e assicurati di fornire loro un'etichetta per il pulsante in modo che non sia un mistero. Questo è stato già fatto in HTML con aria-hidden="true"
su <svg>
e aria-label="Some action"
sui <button>
.
Animazione
È possibile aggiungere vari tipi di animazioni per migliorare l'esperienza utente. Come in altre sfide GUI, configureremo un paio di proprietà personalizzate per contenere lo scopo di un'esperienza con movimento ridotto e un'esperienza con movimento completo. Per impostazione predefinita, gli stili presuppongono che l'utente voglia ridurre il movimento, quindi utilizzando la query media prefers-reduced-motion
scambia 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 e l'ultima variabile --_transition
verrà impostata rispettivamente su --_motion-reduced
o --_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);
}
}
Con quanto sopra, è possibile eseguire la transizione delle modifiche a box-shadow
, background-color
,
transform
e outline-offset
, fornendo all'utente un feedback sull'interfaccia utente che indica che la sua interazione è stata ricevuta.
Aggiungi un po' di stile allo stato :active
modificando leggermente translateY
, in modo da dare al pulsante un bell'effetto di pressione:
.fab {
…
&:active {
@media (prefers-reduced-motion: no-preference) {
transform: translateY(2%);
}
}
}
Infine, passa eventuali 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 ci ho fatto, come faresti‽ 🙂
Diversificaamo i nostri approcci e impariamo tutti i modi per creare sul web.
Crea una demo, twittami i link e io la aggiungerò alla sezione dei remix della community di seguito.
Remix della community
Ancora nessun elemento da visualizzare.
Risorse
- Codice sorgente su GitHub