Podstawowe omówienie tworzenia adaptacyjnego i przystępnego komponentu toast.
W tym poście przedstawię sposoby tworzenia komponentu toast. Zobacz prezentację.
Jeśli wolisz film, oto wersja tego posta w YouTube:
Omówienie
Toasty to nieinteraktywne, pasywne i asynchroniczne krótkie wiadomości dla użytkowników. Zwykle są one używane jako wzór informacji zwrotnej interfejsu, aby poinformować użytkownika o wyniku działania.
Interakcje
Komunikaty różnią się od powiadomień, alertów i promptów, ponieważ nie są interaktywne. Nie można ich zamknąć ani pozostawić. Powiadomienia służą do przekazywania ważnych informacji, przesyłania synchronicznego, które wymagają interakcji, lub komunikatów na poziomie systemu (w przeciwieństwie do treści na poziomie strony). Powiadomienia typu toast są bardziej pasywne niż inne strategie powiadomień.
Znacznik
Element <output>
jest dobrym wyborem do wyświetlania powiadomień, ponieważ jest odczytywany przez czytniki ekranu. Prawidłowy kod HTML stanowi bezpieczną podstawę, którą możemy wzbogacić za pomocą JavaScriptu i CSS.
Toast
<output class="gui-toast">Item added to cart</output>
Jeśli chcesz, możesz dodać role="status"
. Jest to rozwiązanie zastępcze, jeśli przeglądarka nie przypisuje elementom <output>
rola implicit zgodnie ze specyfikacją.
<output role="status" class="gui-toast">Item added to cart</output>
Tosta
Może być wyświetlanych jednocześnie więcej niż 1 toast. Do administrowania wieloma powiadomieniami wykorzystany jest kontener. Ten kontener określa też położenie powiadomień na ekranie.
<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>
Układy
Chcę przypiąć powiadomienia do obszaru inset-block-end
widocznego obszaru. Gdy dodasz więcej powiadomień, będą one układane w stos od krawędzi ekranu.
Kontener GUI
Kontener toastów odpowiada za cały układ toastów. Jest ona fixed
do widoku i korzysta z właściwości logicznej inset
, aby określić, do których krawędzi ma być przypięta, oraz trochę padding
z tej samej krawędzi block-end
.
.gui-toast-group {
position: fixed;
z-index: 1;
inset-block-end: 0;
inset-inline: 0;
padding-block-end: 5vh;
}
Ustawianie się w widocznym obszarze jest też siatką, która może wyrównywać i rozpowszechniać powiadomienia. Elementy są wyśrodkowane jako grupa z atrybutem justify-content
i indywidualnie wyśrodkowane znakiem justify-items
.
Dodaj trochę gap
, aby grzanki się nie stykały.
.gui-toast-group {
display: grid;
justify-items: center;
justify-content: center;
gap: 1vh;
}
Tosty GUI
Pojedynczy toast ma padding
, zaokrąglone rogi z border-radius
oraz funkcję min()
, która ułatwia dostosowanie rozmiaru do urządzeń mobilnych i komputerów. Rozmiar elastyczny w tym kodzie CSS zapobiega powiększaniu się powiadomień do szerokości większej niż 90% obszaru widoku lub 25ch
.
.gui-toast {
max-inline-size: min(25ch, 90vw);
padding-block: .5ch;
padding-inline: 1ch;
border-radius: 3px;
font-size: 1rem;
}
Style
Gdy ustawisz układ i pozycjonowanie, dodaj kod CSS, który pomoże Ci dostosować się do ustawień i interakcji użytkownika.
Kontener z tostem
Tosty nie są interaktywne. Klikanie czy przesuwanie palcem po nich nic nie da, ale obecnie wykorzystują zdarzenia wskaźnika. Aby zapobiec kradzieży kliknięć przez toasty, użyj tego kodu CSS.
.gui-toast-group {
pointer-events: none;
}
Tosty GUI
Nadaj toastom jasny lub ciemny motyw za pomocą właściwości niestandardowych, HSL i zapytania o multimedia z preferencjami.
.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%;
}
}
Animacja
Nowy komunikat powinien pojawiać się na ekranie w ramach animacji.
Zmniejszony ruch można dostosować, ustawiając domyślne wartości translate
na 0
, ale zmieniając wartość animacji na odpowiednią długość w zapytaniu o multimedia w preferencji ruchu . Każdy widzi animację, ale tylko niektórzy użytkownicy widzą toast.
Tutaj są klatki kluczowe używane w animacji wyświetlanej w wyskakującym okienku. CSS będzie kontrolować wejście, oczekiwanie i wyjście toastu w ramach jednej animacji.
@keyframes fade-in {
from { opacity: 0 }
}
@keyframes fade-out {
to { opacity: 0 }
}
@keyframes slide-in {
from { transform: translateY(var(--_travel-distance, 10px)) }
}
Następnie element toast konfiguruje zmienne i zarządza klatkami kluczowymi.
.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
Gdy masz już gotowe style i HTML z dostępnością dla czytników ekranu, potrzebujesz JavaScriptu, aby zarządzać wyświetlaniem, dodawaniem i usuwaniem powiadomień na podstawie zdarzeń użytkownika. Interfejs programisty dla komponentu toast powinien być minimalny i łatwy w użyciu, na przykład:
import Toast from './toast.js'
Toast('My first toast')
Tworzenie grupy toastów i samych toastów
Gdy moduł toast jest wczytywany z JavaScriptu, musi utworzyć kontener toastów i dodać go do strony. Wybrałem dodanie elementu przed elementem body
, co powinno wyeliminować problemy z układaniem elementów z-index
, ponieważ kontener znajduje się nad kontenerem dla wszystkich elementów treści.
const init = () => {
const node = document.createElement('section')
node.classList.add('gui-toast-group')
document.firstElementChild.insertBefore(node, document.body)
return node
}
Funkcja init()
jest wywoływana wewnętrznie w module, a element jest przechowywany jako Toaster
:
const Toaster = init()
Tworzenie elementu HTML komunikatu powoduje funkcja createToast()
. Funkcja wymaga tekstu dla komunikatu toastowego, tworzy element <output>
, ozdabia go za pomocą niektórych klas i atrybutów, ustawia tekst i zwraca węzeł.
const createToast = text => {
const node = document.createElement('output')
node.innerText = text
node.classList.add('gui-toast')
node.setAttribute('role', 'status')
return node
}
Zarządzanie jednym lub wieloma komunikatami toast
JavaScript dodaje teraz do dokumentu kontener na toasty i jest gotowy do dodania utworzonych toastów. Funkcja addToast()
zarządza wyświetlaniem jednego lub wielu komunikatów. Najpierw sprawdza liczbę toastów i czy ruch jest prawidłowy, a potem używa tych informacji, aby dołączyć toast lub wykonać animowanie, aby inne tosty „zrobiły miejsce” dla nowego.
const addToast = toast => {
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
)
Toaster.children.length && motionOK
? flipToast(toast)
: Toaster.appendChild(toast)
}
Podczas dodawania pierwszego komunikatu Toaster.appendChild(toast)
dodaję komunikat do strony, który uruchamia animacje CSS: animacja wejścia, oczekiwanie 3s
, animacja wyjścia.
Funkcja flipToast()
jest wywoływana w przypadku istniejących powiadomień. Wykorzystuje ona technikę FLIP autorstwa Paula Lewisa. Chodzi o obliczenie różnicy w położeniu kontenera, przed i po dodaniu nowego komunikatu.
Wyobraź sobie, że zaznaczasz, gdzie jest toster, gdzie ma się znaleźć, a potem animujesz jego ruch z jednego miejsca do drugiego.
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',
})
}
Siatka CSS odpowiada za układ. Po dodaniu nowego powiadomienia siatka umieszcza go na początku i odstępuje od innych. Tymczasem do animowania kontenera od poprzedniej pozycji jest używana animacja internetowa.
Łączenie wszystkich elementów kodu JavaScript
Gdy wywołana zostanie funkcja Toast('my first toast')
, na stronie zostanie utworzony komunikat toastowy (być może nawet kontener zostanie animowany, aby pomieścić nowy komunikat) i zwrócona zostanie obietnica, a utworzony komunikat toastowy zostanie obserwowany w celu zakończenia animacji CSS (3 animacje kluczowych klatek) w ramach obietnicy.
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()
})
}
Najbardziej myląca część tego kodu to funkcja Promise.allSettled()
i mapowanie toast.getAnimations()
. Użyłem wielu animacji klatek kluczowych w przypadku powiadomienia, więc aby mieć pewność, że wszystkie są gotowe, każdą z nich trzeba zażądać od JavaScriptu, a każdą z ich obietnic finished
należy żądać do końca.
allSettled
działa to w naszym przypadku, ponieważ kończy się, gdy wszystkie obietnice zostaną spełnione. Użycie dyrektywy await Promise.allSettled()
oznacza, że kolejny wiersz kodu może z łatwością usunąć element i zakładać, że wyświetlanie powiadomienia zakończyło się już cyklem życia. Wywołanie resolve()
spełnia ogólną obietnicę tego, że deweloperzy będą mogli posprzątać urządzenie lub zająć się czymś innym po wyświetleniu komunikatu.
export default Toast
Na koniec funkcja Toast
jest eksportowana z modułu, aby inne skrypty mogły ją importować i korzystać z niej.
Korzystanie z komponentu Toast
Aby korzystać z toasta lub funkcji dla deweloperów, należy zaimportować funkcję Toast
i wywołać ją za pomocą ciągu znaków wiadomości.
import Toast from './toast.js'
Toast('Wizard Rose added to cart')
Jeśli deweloper chce wykonać czyszczenie lub inną pracę po wyświetleniu komunikatu toastowego, może użyć asynchronicznego wywołania await.
import Toast from './toast.js'
async function example() {
await Toast('Wizard Rose added to cart')
console.log('toast finished')
}
Podsumowanie
Wiesz już, jak to zrobiłem. Jak Ty? 🙂
Stosujmy różne podejścia i poznajmy sposoby budowania obecności w internecie. Stwórz wersję demonstracyjną, a potem dodam linki do tweetów, a ja dodam ją do poniższej sekcji na temat remiksów na karcie Społeczność.
Remiksy społeczności
- @_developit z kodem HTML/CSS/JS: demonstracja i kod
- Joost van der Schee z HTML/CSS/JS: demo i kod