Toast bileşeni oluşturma

Uyarlanabilir ve erişilebilir bir pop-up bileşeni oluşturmaya dair temel bilgiler.

Bu yayında, bir pop-up bileşeninin nasıl oluşturulacağıyla ilgili düşüncelerimizi paylaşmak istiyoruz. Demoyu deneyin.

Demo

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

Genel Bakış

Bildirimler, kullanıcılara yönelik etkileşimsiz, 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 bildirimi kalıbı olarak kullanılırlar.

Etkileşimler

Bildirimler, uyarılar ve istemler ile karşılaştırıldığında, etkileşimli olmadıkları ve kapatılmaları ya da kalıcı olmaları amaçlanmadığı için pop-up'lar farklıdır. Bildirimler, daha önemli bilgiler, etkileşim gerektiren senkron mesajlar veya sistem düzeyinde mesajlar (sayfa düzeyinin aksine) içindir. Pop-up bildirimler, diğer bildirim stratejilerine kıyasla daha pasiftir.

Brüt kar

<output> öğesi, ekran okuyuculara duyurulduğu için pop-up için iyi bir seçimdir. Doğru HTML, JavaScript ve CSS ile geliştirme yapabileceğimiz güvenli bir temel sağlar. Bu süreçte çok fazla JavaScript kullanacağız.

Bir kadeh

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

role="status" ekleyerek daha kapsayıcı bir içerik oluşturabilirsiniz. Bu, tarayıcı <output> öğelerine spesifikasyona göre örtülü rolü vermezse yedek bir seçenek sunar.

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

Bir tost kapsayıcısı

Aynı anda birden fazla pop-up gösterilebilir. Birden fazla pop-up'ı koordine etmek için bir kapsayıcı kullanılır. Bu kapsayıcı, ekrandaki pop-up'ları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 tercih ettim. Daha fazla bildirim eklenirse bu ekran kenarından yığılır.

GUI kapsayıcısı

Bildirim kapsülü, bildirimlerin gösterilmesiyle ilgili tüm düzen çalışmalarını yapar. Görünüm alanına fixed olan bu öğe, hangi kenarların sabitleneceğini belirtmek için mantıksal mülkü inset ve aynı block-end kenarından biraz padding kullanır.

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

.gui-toast-container öğesinin üzerine yerleştirilmiş DevTools kutu boyutu ve dolgu içeren ekran görüntüsü.

Bildirim kapsayıcısı, görüntü alanında konumlanmanın yanı sıra bildirimleri hizalayabilen ve dağıtabilen bir ızgara kapsayıcısıdır. Öğeler, justify-content ile grup halinde ve justify-items ile ayrı ayrı ortalanır. Tostların birbirine değmemesi için biraz gap ekleyin.

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

Bu kez pop-up grubuna CSS ızgara yer paylaşımının uygulandığı ekran görüntüsü. Bu ekran görüntüsünde pop-up alt öğeleri arasındaki boşluklar vurgulanmıştır.

GUI Kısa İleti

Birer pop-up'ın bazılarında padding, bazılarında border-radius ile daha yumuşak köşeler ve mobil ile masaüstü boyutlandırmasına yardımcı olan bir min() işlevi bulunur. Aşağıdaki CSS'deki duyarlı boyut, pop-up'ların görüntü alanının% 90'ından veya 25ch'den daha geniş olmasını engeller.

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

Dolgulu ve kenarlıklı tek bir .gui-toast öğesinin ekran görüntüsü.

Stiller

Düzen ve yerleşim belirlendikten sonra, kullanıcı ayarlarına ve etkileşimlerine uyum sağlamaya yardımcı olan CSS ekleyin.

Tost kutusu

Bildirimler etkileşimli değildir, üzerine dokunmak veya kaydırarak hareket ettirmek hiçbir şeye yaramaz ancak şu anda işaretçi etkinliklerini tüketir. Aşağıdaki CSS ile pop-up'ların tıklamaları çalmasını önleyin.

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

GUI Kısa İleti

Bildirimlere özel özellikler, HSL ve tercih medya sorgusu içeren açık veya koyu uyarlanabilir bir tema verin.

.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 pop-up, ekrana girerken animasyonla gösterilmelidir. Azaltılmış harekete uyum sağlamak için translate değerleri varsayılan olarak 0 olarak ayarlanır ancak hareket değeri, hareket tercihi medya sorgusunda bir uzunluk değerine güncellenir . Herkes animasyon görür ancak yalnızca bazı kullanıcılar tostların bir mesafe kat etmesini görür.

Pop-up animasyonu için kullanılan animasyon kareleri aşağıda verilmiştir. CSS, pop-up'ın girişini, bekleme süresini 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)) }
}

Ardından pop-up öğ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

Stillerin ve ekran okuyucuya erişilebilir HTML'nin hazır olmasıyla birlikte, kullanıcı etkinliklerine göre pop-up'ların oluşturulmasını, eklenmesini ve kaldırılmasını koordine etmek için JavaScript gerekir. Toast bileşeninin geliştirici deneyimi minimum düzeyde olmalı ve kullanımı kolay olmalıdır. Örneğin:

import Toast from './toast.js'

Toast('My first toast')

Bildirim grubu ve bildirimleri oluşturma

Tost modülü JavaScript'den yüklendiğinde bir tost kapsayıcısı oluşturmalı ve bunu sayfaya eklemelidir. Öğeyi body öğesinden önce eklemeyi tercih ettim. Bu, tüm body öğelerinin kapsayıcısı kapsayıcının üzerinde olduğu için z-index yığın oluşturma sorunlarının olasılığını azaltır.

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 pop-up grubun ekran görüntüsü.

init() işlevi modül 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, pop-up için metin gerektirir, bir <output> öğesi oluşturur, bu öğeyi bazı sınıf 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 pop-up'ı yönetme

JavaScript artık dokümana pop-up'ları içerecek bir kapsayıcı ekliyor ve oluşturulan pop-up'ları eklemeye hazır. addToast() işlevi, bir veya daha fazla pop-up'ın işlenmesini koordine eder. Öncelikle pop-up sayısını ve hareketin uygun olup olmadığını kontrol edin. Ardından bu bilgileri kullanarak pop-up'ı ekleyin veya diğer pop-up'ların yeni pop-up için "yer açtığı" görünmesi için şı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 pop-up'ı eklerken Toaster.appendChild(toast), sayfaya CSS animasyonlarını tetikleyen bir pop-up ekler: animasyonla görün, 3s saniye bekle, animasyonla kaybol. flipToast(), mevcut pop-up'lar olduğunda çağrılır ve Paul Lewis tarafından geliştirilen FLIP adlı bir teknik kullanılır. Buradaki amaç, yeni pop-up eklenmeden önce ve sonra kapsayıcının konumlarındaki farkı hesaplamaktır. Bunu, tost makinesinin şu anda nerede olduğunu, nereye gideceğini işaretleyip bulunduğu yerden bulunduğu yere animasyonla taşımak 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 ızgara, düzeni kaldırır. Yeni bir pop-up eklendiğinde ızgara, pop-up'ı en başa yerleştirir ve diğer pop-up'larla eşit aralıklarla yerleştirir. Bu sırada, kapsayıcının eski konumdan animasyonu için bir web animasyonu kullanılır.

Tüm JavaScript'i bir araya getirme

Toast('my first toast') çağrıldığında bir pop-up oluşturulur, sayfaya eklenir (hatta kapsayıcı yeni pop-up'a uyum sağlamak için animasyonlu hale getirilebilir), bir promise döndürülür ve oluşturulan pop-up, promise çözümü için CSS animasyonunun tamamlanmasını (üç anahtar kare 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şlevi ve toast.getAnimations() eşlemesi olduğunu düşünüyorum. Bildirim için birden fazla anahtar kare animasyonu kullandığımdan, bunların hepsinin tamamlandığından emin olmak için her birinin JavaScript'ten istenmesi ve her birinin finished sözünün tamamlanıp tamamlanmadığının gözlemlenmesi gerekir. allSettled bizim için bu şekilde çalışıyor. Tüm vaatleri yerine getirildiğinde tamamlanmış olarak çözülüyor. await Promise.allSettled() kullanılması, bir sonraki kod satırının öğeyi güvenle kaldırabileceği ve tost mesajının yaşam döngüsünü tamamladığını varsayabileceği anlamına gelir. Son olarak, resolve() çağrısı yüksek düzeyde Toast vaadini yerine getirir. Böylece geliştiriciler, pop-up gösterildikten sonra temizlik yapabilir veya başka işler yapabilir.

export default Toast

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

Toast bileşenini kullanma

Pop-up'ı veya pop-up'ın geliştirici deneyimini kullanmak için Toast işlevi içe aktarılır ve bir mesaj dizesiyle çağrılır.

import Toast from './toast.js'

Toast('Wizard Rose added to cart')

Geliştirici, pop-up gösterildikten sonra temizleme çalışması veya başka bir işlem yapmak istiyorsa async ve await'ı 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 ne yapardınız? 🙂

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

Topluluk remiksleri