Toast bileşeni oluşturma

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

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

Demo

Video tercih ediyorsanız bu yayının YouTube versiyonunu aşağıda bulabilirsiniz:

Genel Bakış

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

Toast bileşeni

Etkileşimler

Toast'lar, etkileşimli olmamaları, kapatılmamaları veya kalıcı olmamaları nedeniyle bildirimlerden, uyarılardan ve istemlerden farklıdır. Bildirimler; daha önemli bilgiler, etkileşim gerektiren eşzamanlı mesajlaşma veya sistem düzeyindeki mesajlar (sayfa düzeyindeki mesajların aksine) için kullanılır. Bildirimler, diğer bildirim stratejilerine kıyasla daha pasiftir.

Brüt kar

<output> öğesi, ekran okuyuculara duyurulduğu için kısa mesaj için iyi bir seçimdir. Doğru HTML, JavaScript ve CSS ile geliştirmemiz için güvenli bir temel sağlar. Çok sayıda JavaScript olacaktır.

Kadeh kaldırma

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

role="status" ekleyerek daha kapsayıcı hale getirebilirsiniz. Bu, tarayıcı spesifikasyona göre <output> öğelerine örtülü rol vermediğinde yedek bir çözüm sağlar.

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

Tost kabı

Aynı anda birden fazla kısa mesaj gösterilebilir. Birden fazla bildirim mesajını düzenlemek için bir kapsayıcı kullanılır. Bu kapsayıcı, ekrandaki kısa mesajların 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

Bildirimleri görüntü alanının inset-block-end kısmına sabitlemeyi seçtim. Başka bildirimler eklenirse bu ekran kenarından itibaren üst üste yerleştirilir.

GUI kapsayıcısı

Toasts kapsayıcısı, toasts'ı sunmak için tüm düzen işlerini yapar. Görüntü alanına fixed ve hangi kenarların sabitleneceğini belirtmek için inset mantıksal özelliğini kullanır. Ayrıca aynı block-end kenarından biraz padding da içerir.

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

Geliştirici Araçları kutu boyutu ve dolgu bilgilerinin .gui-toast-container öğesi üzerinde yer aldığı ekran görüntüsü.

Görüntü alanında konumlanmasının yanı sıra, kısa mesaj kapsayıcısı, kısa mesajları hizalayabilen ve dağıtabilen bir ızgara kapsayıcısıdır. Öğeler, justify-content ile grup olarak ortalanır ve justify-items ile ayrı ayrı ortalanır. Ekmeklerin birbirine değmemesi için biraz gap ekleyin.

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

Bu kez, toast alt öğeleri arasındaki boşluk ve aralıkları vurgulayan, toast grubunda CSS ızgara yerleşimi bulunan ekran görüntüsü.

GUI Toast

Tek bir tostta padding, border-radius ile daha yumuşak köşeler ve mobil cihazlarda ve masaüstünde boyutlandırmaya yardımcı olan bir min() işlevi bulunur. Aşağıdaki CSS'deki duyarlı boyut, bildirimlerin görüntü alanının% 90'ından daha geniş olmasını veya 25ch.

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

Doldurma ve kenarlık yarıçapı gösterilen tek bir .gui-toast öğesinin ekran görüntüsü.

Stiller

Düzen ve konumlandırma ayarlandıktan sonra, kullanıcı ayarlarına ve etkileşimlerine uyum sağlamaya yardımcı olan CSS'yi ekleyin.

Tost kutusu

Bildirimler etkileşimli değildir. Bunlara dokunmak veya bunları kaydırmak herhangi bir işe yaramaz ancak şu anda işaretçi etkinliklerini kullanırlar. Aşağıdaki CSS ile pop-up'ların tıklamaları çalmasını önleyin.

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

GUI Toast

Özel özellikler, HSL ve tercih medya sorgusu ile kısa mesajlara açık veya koyu uyarlanabilir tema uygulayın.

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

Animasyon

Yeni bir bildirim, ekrana girerken animasyonla gösterilmelidir. Hareket azaltma, translate değerlerini varsayılan olarak 0 şeklinde ayarlayarak yapılır ancak hareket değeri, hareket tercihi medya sorgusunda bir uzunluk olarak güncellenir . Herkes animasyon görür ancak yalnızca bazı kullanıcılar toast'ın hareket mesafesini görür.

Bildirim animasyonu için kullanılan animasyon kareleri aşağıda verilmiştir. CSS, pop-up'ın girişini, beklemesini ve çıkışını tek bir animasyonla kontrol eder.

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

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

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

Daha sonra uyarı öğesi 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 okuyucu erişimine uygun HTML hazır olduğunda, kullanıcı etkinliklerine göre bildirimlerin oluşturulması, eklenmesi ve silinmesi için JavaScript gerekir. Toast bileşeninin geliştirici deneyimi minimum düzeyde olmalı ve aşağıdaki gibi kolayca kullanılmaya başlanabilmelidir:

import Toast from './toast.js'

Toast('My first toast')

Bildirim grubu ve bildirimleri oluşturma

Toast modülü JavaScript'ten yüklendiğinde bir toast kapsayıcısı oluşturup sayfaya eklemesi gerekir. Öğeyi body öğesinden önce eklemeyi seçtim. Bu, kapsayıcı tüm gövde öğelerinin kapsayıcısının üzerinde olduğundan z-index yığınlama sorunlarının oluşmasını önler.

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

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

Head ve body etiketleri arasındaki toast grubunun ekran görüntüsü.

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

const Toaster = init()

Toast HTML öğesi oluşturma işlemi createToast() işleviyle yapılır. Bu işlev, bildirim için biraz metin gerektirir, bir <output> öğesi oluşturur, bu öğ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 bildirim mesajını yönetme

JavaScript artık kısa mesajları içeren bir kapsayıcıyı dokümana ekliyor ve oluşturulan kısa mesajları eklemeye hazır. addToast() işlevi, bir veya birden fazla kısa mesajın işlenmesini düzenler. Öncelikle bildirim sayısını ve hareketin uygun olup olmadığını kontrol edin. Ardından, bu bilgileri kullanarak bildirimi ekleyin veya diğer bildirimlerin yeni bildirim için "yer açtığı" izlenimini verecek şekilde şık bir animasyon yapın.

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

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

İlk toast'u eklerken Toaster.appendChild(toast), CSS animasyonlarını tetikleyen sayfaya bir toast ekler: animasyonla görün, 3s bekleyin, animasyonla kaybolun. flipToast(), mevcut bildirimler olduğunda çağrılır ve Paul Lewis tarafından FLIP adı verilen bir teknik kullanılır. Buradaki amaç, yeni bildirim eklenmeden önce ve sonra kapsayıcının konumlarındaki farkı hesaplamaktır. Bunu, ekmek kızartma makinesinin şu anda bulunduğu yeri, gideceği yeri işaretleyip bulunduğu yerden gittiği yere doğru animasyon oluşturmak gibi düşünebilirsiniz.

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

CSS ızgarası, düzenin ağır işlerini yapar. Yeni bir toast eklendiğinde, ızgara bunu başlangıca yerleştirir ve diğerleriyle arasına boşluk koyar. Bu sırada, kapsayıcıyı eski konumundan hareketlendirmek için web animasyonu kullanılır.

Tüm JavaScript'i bir araya getirme

Toast('my first toast') çağrıldığında bir bildirim oluşturulur, sayfaya eklenir (belki de yeni bildirime yer açmak için kapsayıcıya animasyon eklenir), bir promise döndürülür ve oluşturulan bildirim, promise'in çözümlenmesi için CSS animasyonunun tamamlanması (üç anahtar kare animasyonu) açısından 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şlevi ve toast.getAnimations() eşlemesi olduğunu düşünüyorum. Toast için birden fazla anahtar kare animasyonu kullandığımdan hepsinin tamamlandığından emin olmak için her birinin JavaScript'ten istenmesi ve her birinin finished tamamlanma vaatlerine uyulması gerekir. allSettled tüm sözleri yerine getirildiğinde tamamlanmış olarak çözümlenir. await Promise.allSettled() kullanıldığında, sonraki kod satırı öğeyi güvenle kaldırabilir ve kısa mesajın yaşam döngüsünü tamamladığını varsayabilir. Son olarak, resolve() çağrısı üst düzey Toast sözünü yerine getirir. Böylece geliştiriciler, bildirim 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ıp kullanabilmesi için modülden dışa aktarılır.

Toast bileşenini kullanma

Bildirim veya bildirimin geliştirici deneyimi, Toast işlevi içe aktarılıp bir mesaj dizesiyle çağrılarak kullanılır.

import Toast from './toast.js'

Toast('Wizard Rose added to cart')

Geliştirici, kısa mesaj gösterildikten sonra temizlik yapmak veya başka bir işlem gerçekleştirmek istiyorsa asenkron işlevleri ve await işlevini kullanabilir.

import Toast from './toast.js'

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

Sonuç

Bunu nasıl yaptığımı öğrendiğinize göre, siz nasıl yapardınız? 🙂

Yaklaşımlarımızı çeşitlendirelim ve web'de içerik oluşturmanın tüm yollarını öğrenelim. Bir demo oluşturun, bağlantıları bana tweet atın. Ben de bu bağlantıları aşağıdaki topluluk remiksleri bölümüne ekleyeyim.

Topluluk remiksleri