Una panoramica di base su come creare un componente di Toast adattivo e accessibile.
In questo post voglio condividere i miei pensieri su come creare un componente toast. Prova la demo.
Se preferisci i video, ecco una versione di questo post su YouTube:
Panoramica
I toast sono messaggi brevi non interattivi, passivi e asincroni per gli utenti. Generalmente vengono utilizzati come pattern di feedback sull'interfaccia per informare l'utente sui risultati di un'azione.
Interazioni
I toast sono diversi dalle notifiche, avvisi e messaggi perché non sono interattivi, non devono essere ignorate o persistenti. Le notifiche servono per informazioni più importanti, per la messaggistica sincrona che richiede l'interazione o messaggi a livello di sistema (anziché a livello di pagina). I toast sono più passivi delle altre strategie di notifica.
Aumento
La
<output>
è una buona scelta per il toast, perché viene annunciato
lettori. Il codice HTML corretto fornisce una base sicura per migliorare con JavaScript e
e c'è molto codice JavaScript.
Un toast
<output class="gui-toast">Item added to cart</output>
Può essere di più
inclusivo
aggiungendo role="status"
. Ciò fornisce un
di riserva se il browser non fornisce agli elementi <output>
la
ruolo
in base alle specifiche.
<output role="status" class="gui-toast">Item added to cart</output>
Un contenitore dei toast
È possibile visualizzare più toast alla volta. Per orchestrare più elementi viene usato un container. Questo contenitore gestisce anche la posizione toast sullo schermo.
<section class="gui-toast-group">
<output role="status">Wizard Rose added to cart</output>
<output role="status">Self Watering Pot added to cart</output>
</section>
Layout
Ho scelto di fissare i toast
inset-block-end
dall'area visibile e, se vengono aggiunti altri toast, si impilano dal bordo dello schermo.
Container GUI
Il contenitore dei toast si occupa di tutto il lavoro di layout per la presentazione dei toast. È
fixed
all'area visibile e utilizza la proprietà logica
inset
per specificare quale
bordi su cui fissare, più un po' di padding
dallo stesso bordo block-end
.
.gui-toast-group {
position: fixed;
z-index: 1;
inset-block-end: 0;
inset-inline: 0;
padding-block-end: 5vh;
}
Oltre a posizionarsi all'interno dell'area visibile, il contenitore toast è una
contenitore in grado di allineare e distribuire i toast. Gli elementi sono centrati come
gruppo con justify-content
e centrato singolarmente con justify-items
.
Metti un po' di gap
in modo che i toast non si tocchino.
.gui-toast-group {
display: grid;
justify-items: center;
justify-content: center;
gap: 1vh;
}
Toast con GUI
Un singolo toast ha alcuni padding
, alcuni angoli più morbidi con
border-radius
,
e una funzione min()
per
sono utili per il dimensionamento
di dispositivi mobili e computer. Le dimensioni adattabili nel seguente CSS
impedisce che i toast crescano più del 90% dell'area visibile o
25ch
.gui-toast {
max-inline-size: min(25ch, 90vw);
padding-block: .5ch;
padding-inline: 1ch;
border-radius: 3px;
font-size: 1rem;
}
Stili
Dopo aver impostato il layout e il posizionamento, aggiungi CSS che aiutano ad adattarti all'utente impostazioni e interazioni.
Contenitore toast
I toast non sono interattivi, toccare o far scorrere i toast non serve a nulla, attualmente consumano eventi puntatore. Evita che i toast rubino di clic con il seguente CSS.
.gui-toast-group {
pointer-events: none;
}
Toast con GUI
Assegna ai toast un tema adattivo chiaro o scuro con proprietà personalizzate, HSL e un query supporti preferenze.
.gui-toast {
--_bg-lightness: 90%;
color: black;
background: hsl(0 0% var(--_bg-lightness) / 90%);
}
@media (prefers-color-scheme: dark) {
.gui-toast {
color: white;
--_bg-lightness: 20%;
}
}
Animazione
Dovrebbe apparire un nuovo avviso popup con un'animazione quando entra nella schermata.
La gestione del movimento ridotto avviene impostando i valori di translate
su 0
entro il
il valore predefinito, ma aggiorna il valore di movimento a una lunghezza in un contenuto multimediale con preferenze di movimento
query . Tutti ricevono un'animazione, ma solo alcuni utenti hanno l'occasione di toast
una distanza.
Di seguito sono riportati i fotogrammi chiave utilizzati per l'animazione toast. Il CSS controllerà i l'ingresso, l'attesa e l'uscita del toast, il tutto in un'unica animazione.
@keyframes fade-in {
from { opacity: 0 }
}
@keyframes fade-out {
to { opacity: 0 }
}
@keyframes slide-in {
from { transform: translateY(var(--_travel-distance, 10px)) }
}
L'elemento toast imposta quindi le variabili e orchestra i fotogrammi chiave.
.gui-toast {
--_duration: 3s;
--_travel-distance: 0;
will-change: transform;
animation:
fade-in .3s ease,
slide-in .3s ease,
fade-out .3s ease var(--_duration);
}
@media (prefers-reduced-motion: no-preference) {
.gui-toast {
--_travel-distance: 5vh;
}
}
JavaScript
Con gli stili e l'HTML accessibile allo screen reader pronti, JavaScript è necessario per orchestrare la creazione, l'aggiunta e la distruzione dei toast in base alle eventi. L'esperienza degli sviluppatori con il componente toast deve essere minima e iniziare con facilità, come in questo esempio:
import Toast from './toast.js'
Toast('My first toast')
Creazione del gruppo toast e dei toast
Quando il modulo toast viene caricato da JavaScript, deve creare un contenitore toast.
e aggiungerla alla pagina. Ho scelto di aggiungere l'elemento prima di body
, in questo modo
È improbabile che si verifichino problemi di sovrapposizione di z-index
perché il container si trova al di sopra del container per
a tutti gli elementi del corpo.
const init = () => {
const node = document.createElement('section')
node.classList.add('gui-toast-group')
document.firstElementChild.insertBefore(node, document.body)
return node
}
La funzione init()
viene chiamata internamente al modulo, archiviando l'elemento
come Toaster
:
const Toaster = init()
La creazione di elementi HTML toast viene completata con la funzione createToast()
. La
richiede del testo per il toast, crea un elemento <output>
, adorna
con alcune classi e attributi, imposta il testo e restituisce il nodo.
const createToast = text => {
const node = document.createElement('output')
node.innerText = text
node.classList.add('gui-toast')
node.setAttribute('role', 'status')
return node
}
Gestione di uno o più toast
Ora JavaScript aggiunge al documento un contenitore per i toast e viene
per aggiungere i toast creati. La funzione addToast()
orchestra la gestione di uno
o molti toast. Innanzitutto, controlla il numero di toast e se il movimento è corretto,
poi useremo queste informazioni per aggiungere il toast o per fare qualche idea
in modo che gli altri toast appaiano "fare spazio" per il nuovo brindisi.
const addToast = toast => {
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
)
Toaster.children.length && motionOK
? flipToast(toast)
: Toaster.appendChild(toast)
}
Quando aggiungi il primo toast, Toaster.appendChild(toast)
aggiunge un toast al
pagina che attiva le animazioni CSS: anima in entrata, attendi 3s
, anima in uscita.
flipToast()
viene chiamato quando sono presenti toast esistenti, utilizzando una tecnica
chiamata FLIP da Paul
Lewis. L'idea è calcolare la differenza
nelle posizioni del contenitore, prima e dopo l'aggiunta del nuovo avviso popup.
È come contrassegnare il luogo in cui si trova ora il tostapane, quindi
e si anima dalla posizione in cui si trova.
const flipToast = toast => {
// FIRST
const first = Toaster.offsetHeight
// add new child to change container size
Toaster.appendChild(toast)
// LAST
const last = Toaster.offsetHeight
// INVERT
const invert = last - first
// PLAY
const animation = Toaster.animate([
{ transform: `translateY(${invert}px)` },
{ transform: 'translateY(0)' }
], {
duration: 150,
easing: 'ease-out',
})
}
La griglia CSS esegue il sollevamento del layout. Quando viene aggiunto un nuovo toast, viene inserito nella griglia all'inizio e lo spazia tra le altre. Nel frattempo, un animazione è utilizzata per animare il contenitore dalla vecchia posizione.
Mettere insieme tutto il codice JavaScript
Quando viene chiamato Toast('my first toast')
, viene creato un avviso popup e aggiunto alla pagina
(forse anche il contenitore è animato per accogliere il nuovo toast), un
promettere
e il toast creato viene restituito
guardato per
Completamento dell'animazione CSS (le tre animazioni di fotogrammi chiave) per una risoluzione promessa.
const Toast = text => {
let toast = createToast(text)
addToast(toast)
return new Promise(async (resolve, reject) => {
await Promise.allSettled(
toast.getAnimations().map(animation =>
animation.finished
)
)
Toaster.removeChild(toast)
resolve()
})
}
Ho pensato che la parte confusa di questo codice fosse nella funzione Promise.allSettled()
e toast.getAnimations()
. Dato che ho usato diverse animazioni di fotogrammi chiave
per il toast, per sapere con sicurezza che tutti hanno finito, ognuna deve
da JavaScript e ognuno dei suoi
finished
promesse osservate per il completamento.
allSettled
se lo fa per noi, risolvendosi come completa una volta tutte le sue promesse
sono state soddisfatte. Se utilizzi await Promise.allSettled()
, la riga successiva
può rimuovere con sicurezza l'elemento e presumere che l'avviso popup abbia
durante il ciclo di vita di attività. Infine, chiamare il numero resolve()
soddisfa la promessa di Toast di alto livello,
gli sviluppatori possono eseguire la pulizia o svolgere altre operazioni una volta visualizzato il messaggio popup.
export default Toast
Infine, la funzione Toast
viene esportata dal modulo, per gli altri script in
importare e usare.
Utilizzo del componente Toast
L'utilizzo del toast, o dell'esperienza da sviluppatore del toast, avviene importando
Toast
e chiamandola con una stringa di messaggio.
import Toast from './toast.js'
Toast('Wizard Rose added to cart')
Se lo sviluppatore vuole eseguire operazioni di pulizia o altro, dopo il toast possono usare le parole asincrone attendi.
import Toast from './toast.js'
async function example() {
await Toast('Wizard Rose added to cart')
console.log('toast finished')
}
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 con i link e la aggiungerò alla sezione dei remix della community qui sotto.
Remix della community
- @_developit con HTML/CSS/JS: demo & codice
- Joost van der Schee con HTML/CSS/JS: demo e codice