Bölünmüş metin animasyonları oluşturma

Bölünmüş harf ve kelime animasyonlarının nasıl oluşturulacağına ilişkin temel bir genel bakış.

Bu yazıda, web için bölünmüş metin animasyonlarının ve etkileşimlerin minimal, erişilebilir ve tarayıcılar arasında çalışacak şekilde nasıl çözüleceğine dair düşüncelerimi 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ış

Bölünmüş metin animasyonları etkileyici olabilir. Bu gönderide animasyon potansiyelini çok az anlayacağız, ancak bunlar üzerinde ilerlemek için bir temel oluşturacaktır. Amaç, animasyonları kademeli olarak oluşturmaktır. Metin, varsayılan olarak okunabilir olmalı, animasyon en üst kısma yerleştirilmelidir. Bölünmüş metin hareketi efektleri müthiş ve rahatsız edici olabilir. Bu nedenle, yalnızca HTML'yi değiştirir veya hareket stillerini kullanıcı hareketi kabul ediyorsa uygularız.

Aşağıda, iş akışına ve sonuçlara genel bir bakış verilmiştir:

  1. CSS ve JS için azaltılmış hareket koşullu değişkenleri hazırlayın.
  2. JavaScript'te bölünmüş metin yardımcı programlarını hazırlayın.
  3. Sayfa yüklemede koşulları ve yardımcı programları düzenleyin.
  4. Harfler ve kelimeler (rad kısmı!) için CSS geçişleri ve animasyonları yazın.

Kullanacağımız koşullu sonuçların önizlemesini burada bulabilirsiniz:

Nesne paneli açık ve azaltılmış hareket 'azalt'a ayarlı ve h1 bölünmemiş olarak gösterilen Chrome geliştirici araçlarının ekran görüntüsü
Kullanıcı daha az hareket tercih eder: Metin okunaklı / bozulmamış

Kullanıcı daha az hareket etmeyi tercih ederse HTML belgesini olduğu gibi bırakırız ve animasyon yapmayız. Hareket uygunsa onu parçalara ayırırız. JavaScript kodu harf harf böldükten sonra gösterilen HTML'nin önizlemesini burada görebilirsiniz.

Nesne paneli açık ve azaltılmış hareket 'azalt'a ayarlı ve h1 bölünmemiş olarak gösterilen Chrome geliştirici araçlarının ekran görüntüsü
Kullanıcı hareket edebilir. Metin birden fazla <span> öğesine bölündü

Hareket koşulları hazırlanıyor

Kolaylıkla kullanılabilir @media (prefers-reduced-motion: reduce) medya sorgusu bu projede CSS ve JavaScript'ten kullanılır. Bu medya sorgusu, metnin bölünüp bölünmeyeceğine karar verdiğimiz birincil koşuldur. Geçişleri ve animasyonları durdurmak için CSS medya sorgusu kullanılır. HTML manipülasyonunu durdurmak için ise JavaScript medya sorgusu kullanılır.

CSS koşulunu hazırlama

Medya Sorguları Düzey 5 söz dizimini etkinleştirmek için PostCSS kullandım. Burada, medya sorgusu boole'sini bir değişkende depolayabilirim:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

JS koşulunu hazırlama

JavaScript'te tarayıcı, medya sorgularını kontrol etmek için bir yol sağlar. Medya sorgusu kontrolünden boole sonucunu çıkarıp yeniden adlandırmak için destructuring özelliğini kullandım:

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

Bu durumda motionOK için test yapabilir ve dokümanı yalnızca kullanıcı hareketi azaltmayı talep etmediyse değiştirebilirim.

if (motionOK) {
  // document split manipulations
}

Aynı değeri, Yuvalama Taslağı 1'deki @nest söz dizimini etkinleştirmek için PostCSS kullanarak kontrol edebilirim. Bu, animasyonla ilgili tüm mantığı ve üst öğe ile alt öğeler için stil gereksinimlerini tek bir yerde depolamamı sağlıyor:

letter-animation {
  @media (--motionOK) {
    /* animation styles */
  }
}

PostCSS özel özelliği ve bir JavaScript boole özelliği sayesinde, etkiyi koşullu olarak yeni sürüme geçirmeye hazırız. Böylece, dizeleri öğelere dönüştürmek için kullanılan JavaScript’i inceleyeceğimiz bir sonraki bölüme geçiyoruz.

Metin Bölme

Metin harfleri, kelimeler, satırlar vb. CSS veya JS ile tek tek canlandırılamaz. Etkiyi elde etmek için kutulara ihtiyacımız var. Bir harfi canlandırmak istiyorsak her harfin bir öğe olması gerekir. Her kelimeyi canlandırmak istiyorsak her kelimenin birer öğe olması gerekir.

  1. Dizeleri öğelere bölmek için JavaScript yardımcı program işlevleri oluşturma
  2. Bu yardımcı programların kullanımını düzenleyin

Harfleri bölme yardımcı işlevi

Bir dizeyi alıp dizideki her harfi döndüren bir işlevle başlamak eğlenceli bir başlangıçtır.

export const byLetter = text =>
  [...text].map(span)

ES6'nın yaygın söz dizimi bu süreci hızlı bir hale getirmeye yardımcı oldu.

Kelimeleri bölme yardımcı işlevi

Harfleri bölmeye benzer şekilde, bu işlev bir dizeyi alır ve bir dizideki her kelimeyi döndürür.

export const byWord = text =>
  text.split(' ').map(span)

JavaScript dizelerindeki split() yöntemi, dilim hangi karakterlere göre ayrılacağını belirtmemize olanak tanır. Kelimelerin bölündüğünü gösteren boş bir boşluğu geçtim.

Kutu yapımında yardımcı program işlevi

Efekt, her harf için kutu gerektirir ve bu işlevlerde map() öğesinin bir span() işleviyle çağrıldığını görürüz. span() fonksiyonu.

const span = (text, index) => {
  const node = document.createElement('span')

  node.textContent = text
  node.style.setProperty('--index', index)

  return node
}

Dizi konumuyla --index adlı özel özelliğin ayarlandığını unutmamak çok önemlidir. Harf animasyonları için kutulara sahip olmak harika bir özelliktir ancak CSS'de kullanılacak bir dizine sahip olmak, görünüşte büyük etkiye sahip olan küçük bir eklemedir. Bu büyük etkide en önemlisi kafa karıştırıcı olmasıdır. Kademeli bir görünüm için animasyonları dengeleme yöntemi olarak --index kullanabiliriz.

Yardımcı programlar sonuç

splitting.js modülü tamam:

const span = (text, index) => {
  const node = document.createElement('span')

  node.textContent = text
  node.style.setProperty('--index', index)

  return node
}

export const byLetter = text =>
  [...text].map(span)

export const byWord = text =>
  text.split(' ').map(span)

Şimdi de bu byLetter() ve byWord() işlevlerini içe aktarıp kullanmak var.

Bölünmüş düzenleme

Bölme yardımcı programları kullanıma hazır olduğundan, hepsini bir araya getirmek şu anlama gelir:

  1. Bölünecek öğeleri bulma
  2. Bunları bölme ve metni HTML ile değiştirme

Bundan sonra CSS devralınır ve öğeleri / kutuları canlandırır.

Bulgu Öğeleri

İstenen animasyon ve metnin nasıl bölüneceği hakkındaki bilgileri saklamak için özellikler ve değerler kullanmayı seçtim. Bu bildirim temelli seçenekleri HTML'ye yerleştirmekten hoşlandım. split-by özelliği, JavaScript'te öğeleri bulmak ve harfler ya da kelimeler için kutular oluşturmak için kullanılır. letter-animation veya word-animation özelliği, CSS'den öğe alt öğelerini hedeflemek ve dönüşümler ile animasyonlar uygulamak için kullanılır.

Aşağıda, iki özelliği gösteren bir HTML örneği verilmiştir:

<h1 split-by="letter" letter-animation="breath">animated letters</h1>
<h1 split-by="word" word-animation="trampoline">hover the words</h1>

JavaScript'ten öğe bulma

Metninin bölünmesini isteyen öğelerin listesini toplamak amacıyla özellik varlığı için CSS seçici söz dizimini kullandım:

const splitTargets = document.querySelectorAll('[split-by]')

CSS'den öğe bulma

Ayrıca, tüm harf animasyonlarına aynı temel stilleri vermek için CSS'deki özellik varlığı seçiciyi de kullandım. Daha sonra, bir efekt elde etmek üzere daha spesifik stiller eklemek için özellik değerini kullanacağız.

letter-animation {
  @media (--motionOK) {
    /* animation styles */
  }
}

Metin bölünüyor

JavaScript'te bulduğumuz bölünmüş hedeflerin her biri için metinlerini özelliğin değerine göre böler ve her dizeyi bir <span> ile eşleriz. Daha sonra öğenin metnini hazırladığımız kutularla değiştirebiliriz:

splitTargets.forEach(node => {
  const type = node.getAttribute('split-by')
  let nodes = null

  if (type === 'letter') {
    nodes = byLetter(node.innerText)
  }
  else if (type === 'word') {
    nodes = byWord(node.innerText)
  }

  if (nodes) {
    node.firstChild.replaceWith(...nodes)
  }
})

Düzenleme sonucu

index.js tamamlandı:

import {byLetter, byWord} from './splitting.js'

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

if (motionOK) {
  const splitTargets = document.querySelectorAll('[split-by]')

  splitTargets.forEach(node => {
    const type = node.getAttribute('split-by')
    let nodes = null

    if (type === 'letter')
      nodes = byLetter(node.innerText)
    else if (type === 'word')
      nodes = byWord(node.innerText)

    if (nodes)
      node.firstChild.replaceWith(...nodes)
  })
}

JavaScript şu İngilizce dilinde okunabilir:

  1. Bazı yardımcı yardımcı program işlevlerini içe aktarın.
  2. Hiçbir şey yapmazsanız bu kullanıcının hareketin doğru olup olmadığını kontrol edin.
  3. Bölünmek isteyen her bir öğe için.
    1. Tercihlerine göre bölme.
    2. Metni öğelerle değiştirin.

Animasyonları ve geçişleri bölme

Yukarıdaki belge bölme işlemi, CSS veya JavaScript ile çok sayıda potansiyel animasyonun ve efektin kilidini açtı. Bu makalenin alt kısmında, bölünme potansiyelinizi belirlemenize yardımcı olacak birkaç bağlantı bulunmaktadır.

Bununla neler yapabileceğinizi göstermenin zamanı geldi! CSS tarafından yönlendirilen 4 animasyon ve geçiş paylaşacağım. 🤓

Harfleri böl

Bölünmüş harf efektlerinin temeli olarak aşağıdaki CSS'yi faydalı buldum. Tüm geçişleri ve animasyonları hareketli medya sorgusunun arkasına yerleştiriyorum, ardından her yeni alt harfe (span) bir görüntüleme özelliği ile boşluklarla ne yapılacağına ilişkin bir stil veriyorum:

[letter-animation] > span {
  display: inline-block;
  white-space: break-spaces;
}

Boşluk stili, yalnızca boşluk olan aralıkların düzen motoru tarafından daraltılmaması için önemlidir. Şimdi durum bilgili ve eğlenceli şeylere geçelim.

Ayrı geçiş harflerine örnek

Bu örnekte, bölünmüş metin efekti için CSS geçişleri kullanılmaktadır. Geçişlerde, motorun animasyonları için durumlar gerekir ve ben üç durum seçtim: Üzerine gelme, cümle içinde imleçle üzerine gelme, bir harfin üzerine gelme.

Kullanıcı cümlenin, yani container'ın üzerine geldiğinde, tüm alt öğelerin ölçeğini kullanıcı onları uzaklaştırmış gibi küçültüyorum. Ardından, kullanıcı bir mektubun üzerine geldiğinde onu öne çıkarıyorum.

@media (--motionOK) {
  [letter-animation="hover"] {
    &:hover > span {
      transform: scale(.75);
    }

    & > span {
      transition: transform .3s ease;
      cursor: pointer;

      &:hover {
        transform: scale(1.25);
      }
    }
  }
}

Bölünmüş harflere animasyon ekleme örneği

Bu örnekte, her bir harfi sonsuz sayıda canlandırmak için önceden tanımlanmış bir @keyframe animasyonu kullanılır ve bir sıralama efekti oluşturmak için satır içi özel özellik dizininden yararlanılır.

@media (--motionOK) {
  [letter-animation="breath"] > span {
    animation:
      breath 1200ms ease
      calc(var(--index) * 100 * 1ms)
      infinite alternate;
  }
}

@keyframes breath {
  from {
    animation-timing-function: ease-out;
  }
  to {
    transform: translateY(-5px) scale(1.25);
    text-shadow: 0 0 25px var(--glow-color);
    animation-timing-function: ease-in-out;
  }
}

Kelimeleri böl

Buradaki örneklerde Flexbox bir container türü görevi gördü. ch birimini sağlıklı bir boşluk uzunluğu olarak kullandı.

word-animation {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1ch;
}
Kelimeler arasındaki boşluğu gösteren Flexbox geliştirici araçları

Geçişli bölme kelimeleri örneği

Bu geçiş örneğinde tekrar fareyle üzerine gelme özelliğini kullanıyorum. Efekt, fareyle üzerine gelinceye kadar içeriği başlangıçta gizlediğinden etkileşim ve stillerin yalnızca cihazın üzerine gelme yeteneği olduğunda uygulanmasını sağladım.

@media (hover) {
  [word-animation="hover"] {
    overflow: hidden;
    overflow: clip;

    & > span {
      transition: transform .3s ease;
      cursor: pointer;

      &:not(:hover) {
        transform: translateY(50%);
      }
    }
  }
}

Bölünmüş kelime animasyonu örneği

Bu animasyon örneğinde, normal bir metin paragrafı üzerinde kademeli bir sonsuz animasyon oluşturmak için tekrar CSS @keyframes kullanıyorum.

[word-animation="trampoline"] > span {
  display: inline-block;
  transform: translateY(100%);
  animation:
    trampoline 3s ease
    calc(var(--index) * 150 * 1ms)
    infinite alternate;
}

@keyframes trampoline {
  0% {
    transform: translateY(100%);
    animation-timing-function: ease-out;
  }
  50% {
    transform: translateY(0);
    animation-timing-function: ease-in;
  }
}

Sonuç

Nasıl yaptığımı artık bildiğine göre sen ne yaparsın? 🙂

Yaklaşımlarımızı çeşitlendirelim ve web'de geliştirme yapmanın tüm yollarını öğrenelim. Codepen oluşturun veya kendi demonuzu yayınlayın, bana tweet gönderin. Bu kodu aşağıdaki Topluluk remiksleri bölümüne ekleyeceğim.

Kaynak

Daha fazla demo ve ilham verici fikirler

Topluluk remiksleri