Toast bileşeni oluşturma

Uyarlanabilir ve erişilebilir durum mesajı bileşeninin nasıl oluşturulacağına dair temel bir genel bakış.

Bu yayında, bir tost bileşeninin nasıl oluşturulacağıyla ilgili düşünceleri paylaşmak istiyorum. Demoyu deneyin.

Tanıtım

Videoyu tercih ediyorsanız bu yayının YouTube sürümünü burada bulabilirsiniz:

Genel bakış

Durum bilgileri, kullanıcılar için etkileşimli, pasif ve eşzamansız kısa mesajlardır. Bunlar genellikle kullanıcıyı bir işlemin sonuçları hakkında bilgilendirmek için arayüz geri bildirim kalıbı olarak kullanılır.

Etkileşimler

Durum bildirimleri; bildirimlerden, uyarılardan ve istemlerden farklıdır. Bunlar etkileşimli olmadıkları için kapatılmak veya kullanılmak üzere tasarlanmamıştır. Bildirimler daha önemli bilgiler, etkileşim gerektiren eşzamanlı mesajlar veya (sayfa düzeyinde değil) sistem düzeyinde mesajlar içindir. Durum bildirimleri, diğer bildirim stratejilerinden daha pasiftir.

Markup

<output> öğesi, ekran okuyuculara duyurulduğundan durum mesajı için iyi bir seçimdir. Doğru HTML, JavaScript ve CSS ile geliştirme yapmamız için güvenli bir temel oluşturur ve çok fazla JavaScript olacaktır.

Kadeh tost

<output class="gui-toast">Item added to cart</output>

role="status" ekleyerek daha kapsayıcı olabilirsiniz. Tarayıcı, <output> öğelerine spesifikasyona göre dolaylı rolü vermezse bu işlem bir yedek sağlar.

<output role="status" class="gui-toast">Item added to cart</output>

Durum mesajı kutusu

Aynı anda birden fazla durum mesajı gösterilebilir. Birden fazla toast düzenlemek için bir container kullanılır. Bu kapsayıcı, kısa mesajların ekrandaki konumunu da yönetir.

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

Düzenler

İletileri görüntü alanının inset-block-end öğesine sabitlemeyi seçtim ve daha fazla durum mesajı eklenirse bunlar ekran kenarından yığılıyor.

GUI kapsayıcısı

Durum özeti kapsayıcısı, kısa tostların sunulması için gereken tüm düzen işlerini yapar. Görüntü alanı için fixed değerine sahiptir ve hangi kenarların sabitleneceğini belirlemek için inset mantıksal özelliğini ve aynı block-end kenarından biraz padding özelliğini kullanır.

.gui-toast-group {
  position: fixed;
  z-index: 1;
  inset-block-end: 0;
  inset-inline: 0;
  padding-block-end: 5vh;
}

DevTools kutu boyutunu ve .gui-toast-container öğesine yer paylaşımlı dolguyu gösteren ekran görüntüsü.

Kendisini görüntü alanının içinde konumlandırmanın yanı sıra, durum mesajı öğelerini hizalayıp dağıtabilen bir ızgara kapsayıcısıdır. Öğeler, justify-content ile bir grup olarak ve justify-items ile ayrı ayrı ortalanır. Tostların birbirine değmemesi için biraz gap koyun.

.gui-toast-group {
  display: grid;
  justify-items: center;
  justify-content: center;
  gap: 1vh;
}

Durum mesajı grubunda CSS ızgara yer paylaşımını gösteren ekran görüntüsü. Bu kez, kısa mesaj alt öğeleri arasındaki boşluk ve boşluklar vurgulanıyor.

GUI Bildirim Mesajı

Bağımsız bir kısa mesajın padding, köşeleri daha yumuşak border-radius köşelerinin yanı sıra mobil ile masaüstünün boyutlandırılmasına yardımcı olan min() işlevine sahiptir. Aşağıdaki CSS'de yer alan duyarlı boyut, durum mesajının görüntü alanının% 90'ından veya 25ch'ından daha geniş bir alana genişlemesini önler.

.gui-toast {
  max-inline-size: min(25ch, 90vw);
  padding-block: .5ch;
  padding-inline: 1ch;
  border-radius: 3px;
  font-size: 1rem;
}

Dolgu ve kenarlık yarıçapının gösterildiği tek bir .gui-toast öğesinin ekran görüntüsü.

Stiller

Düzen ve konumlandırma ayarlandığında kullanıcı ayarlarına ve etkileşimlere uyum sağlamaya yardımcı olacak CSS ekleyin.

Bilgi kutusu

Bilgilendirmeler etkileşimli değildir. Dokunulduğunda veya kaydırıldığında herhangi bir şey yapılmıyor, ancak şu anda işaretçi etkinlikleri kullanılıyor. Aşağıdaki CSS ile durum mesajının tıklamaları çalmasını önleyin.

.gui-toast-group {
  pointer-events: none;
}

GUI Bildirim Mesajı

Kısa toastlara özel özellikler, HSL ve bir tercih medya sorgusu ile açık veya koyu bir uyarlanabilir tema ekleyin.

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

Animasyonlar

Yeni kısa mesaj, ekrana girerken bir animasyonla görüntülenecektir. Azaltılmış hareketin karşılanması, translate değerlerinin varsayılan olarak 0 değerine ayarlanması ancak hareket tercihi medya sorgusunda hareket değerinin belirli bir uzunlukta güncellenmesiyle yapılır . Herkes animasyon alıyor, ancak yalnızca bazı kullanıcılar kadeh kaldırıp belirli bir mesafe yol katediyor.

Kısa ileti animasyonu için kullanılan animasyon kareleri burada verilmiştir. CSS, durum mesajının girişini, beklemeyi ve çıkışını tek bir animasyonda kontrol eder.

@keyframes fade-in {
  from { opacity: 0 }
}

@keyframes fade-out {
  to { opacity: 0 }
}

@keyframes slide-in {
  from { transform: translateY(var(--_travel-distance, 10px)) }
}

Durum mesajı öğesi daha sonra değişkenleri ayarlar ve animasyon karelerini düzenler.

.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

Stiller ve ekran okuyucuyla erişilebilen HTML hazır olduğunda, kısa mesajların kullanıcı etkinliklerine dayalı olarak oluşturulmasını, eklenmesini ve kaldırılmasını düzenlemek için JavaScript gerekir. Durum mesajı bileşeninin geliştirici deneyimi aşağıdaki gibi minimum düzeyde ve kolay bir şekilde başlatılmalıdır:

import Toast from './toast.js'

Toast('My first toast')

Durum mesajı grubu ve kısa mesaj oluşturma

Durum mesajı modülü JavaScript'ten yüklendiğinde, bir durum mesajı kapsayıcısı oluşturmalı ve bunu sayfaya eklemelidir. Öğeyi body tarihinden önce eklemeyi seçtim. Container, tüm gövde öğelerinde kapsayıcının üzerinde olduğundan z-index yığınlandırma sorunu yaşanma ihtimali artar.

const init = () => {
  const node = document.createElement('section')
  node.classList.add('gui-toast-group')

  document.firstElementChild.insertBefore(node, document.body)
  return node
}

Başlık ve gövde etiketleri arasındaki durum mesajı grubunun ekran görüntüsü.

init() işlevi, modülün içinde çağrılır ve öğeyi Toaster olarak saklar:

const Toaster = init()

Toast HTML öğesi oluşturma işlemi createToast() işleviyle yapılır. İşlev, durum mesajı için biraz metin gerektirir, bir <output> öğesi oluşturur, öğeyi bazı sınıflar ve özelliklerle süsler, metni ayarlar ve düğümü döndürür.

const createToast = text => {
  const node = document.createElement('output')
  
  node.innerText = text
  node.classList.add('gui-toast')
  node.setAttribute('role', 'status')

  return node
}

Bir veya daha fazla durum mesajı yönetme

JavaScript, artık tostları içermek için dokümana bir kapsayıcı ekler ve oluşturulan durum mesajlarını eklemeye hazırdır. addToast() işlevi, bir veya daha fazla durum mesajı işlemeyi düzenler. Önce tost sayısını ve hareketin uygun olup olmadığını kontrol edin. Sonra bu bilgileri kullanarak tost ekimi ekleyin ya da eğlenceli animasyonlar yapın. Böylece diğer tost ekmeği yeni tost için "yer aç"mış gibi görünür.

const addToast = toast => {
  const { matches:motionOK } = window.matchMedia(
    '(prefers-reduced-motion: no-preference)'
  )

  Toaster.children.length && motionOK
    ? flipToast(toast)
    : Toaster.appendChild(toast)
}

İlk durum mesajı eklenirken Toaster.appendChild(toast), CSS animasyonlarını tetikleyen sayfaya bir durum mesajı ekler: canlandır, bekle, 3s, canlandır. Mevcut kısa ileti olduğunda flipToast() çağrılır ve Paul Lewis tarafından FLIP adı verilen bir teknik kullanılır. Burada amaç, yeni durum mesajı eklenmeden önceki ve eklendikten sonra kapsayıcının konumları arasındaki farkı hesaplamaktır. Bunu, Tost Makinesi'nin şu anda nerede olduğunu ve nerede olacağını işaretleyip nereden geldiğine animasyon eklemek gibi düşünün.

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',
  })
}

Düzeni kaldırma işlemini CSS ızgarası yapar. Yeni bir kısa mesaj eklendiğinde, ızgara en başa koyar ve diğerleriyle boşluk bırakır. Bu arada, kapsayıcıyı eski konumundan canlandırmak için bir web animasyonu kullanılır.

Tüm JavaScript'i bir araya getirmek

Toast('my first toast') çağrıldığında, bir durum mesajı oluşturulur, sayfaya eklenir (belki de kapsayıcı animasyon yeni durum mesajı yerleştirmek için canlandırma yapılır), bir vaadi döndürülür ve vadetilen çözüm için CSS animasyonunun tamamlanması (üç animasyon karesi animasyonu) için bir vaad döndürülür ve oluşturulan kısa mesaj (üç animasyon karesi animasyonu) izlenir.

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() 
  })
}

Bu kodun kafa karıştırıcı kısmının Promise.allSettled() işlevinde ve toast.getAnimations() eşlemesinde olduğunu hissettim. Kısa ileti için birden fazla animasyon karesi animasyonu kullandığım için hepsinin bittiğini rahatça öğrenmek amacıyla her birinin JavaScript'ten istenmesi ve tamamlanma için gözlemlenen finished vaatlerinin her biri olması gerekir. allSettled bizim için bunu yapar ve tüm vaatleri yerine getirildiğinde kendini tamamlanmış olarak çözümler. await Promise.allSettled() kullanılması, bir sonraki kod satırının öğeyi güvenle kaldırabileceği ve durum mesajının kullanım ömrünü tamamladığını varsayabileceği anlamına gelir. Son olarak, resolve() çağrısı, üst düzey Toast sözünü yerine getirir. Böylece geliştiriciler, tost gösterildikten sonra temizlik yapabilir veya başka işler yapabilir.

export default Toast

Son olarak, Toast işlevi diğer komut dosyalarının içe aktarılıp kullanılması için modülden dışa aktarılır.

Toast bileşenini kullanma

Durum mesajının veya kısa mesajın geliştirici deneyiminin kullanılması için Toast işlevi içe aktarılıp bir mesaj dizesiyle çağrılır.

import Toast from './toast.js'

Toast('Wizard Rose added to cart')

Geliştirici, işleri temizlemek veya başka bir şey yapmak isterse, durum mesajı gösterildikten sonra eşzamansız ve await özelliğini kullanabilir.

import Toast from './toast.js'

async function example() {
  await Toast('Wizard Rose added to cart')
  console.log('toast finished')
}

Sonuç

Nasıl yaptığımı artık bildiğine göre siz de nasıl yapardınız? 🙂

Yaklaşımlarımızı çeşitlendirelim ve web'de geliştirme yapmanın tüm yollarını öğrenelim. Bir demo oluşturun, bana tweet atın bağlantıları, aşağıdaki topluluk remiksleri bölümüne ekleyeceğim.

Topluluk remiksleri