Tworzenie animacji podzielonego tekstu

Podstawowe informacje o tworzeniu animacji podzielonych liter i słów.

W tym poście przedstawię sposoby rozwiązywania problemów z interakcjami i animacjami podzielonego tekstu w internecie, które są jak najmniejsze, dostępne i działają w różnych przeglądarkach. Zobacz prezentację.

Demonstracja

Jeśli wolisz film, oto wersja tego posta na YouTube:

Przegląd

Animacje podzielonego tekstu mogą być niesamowite. W tym poście nie omówimy potencjału animacji, ale stanowi podstawę do budowania. Celem jest stopniowa animacja. Domyślnie tekst powinien być czytelny, a animacja umieszczona na jego górze. Efekty ruchu podzielonego tekstu mogą być ekstrawaganckie i potencjalnie uciążliwe, dlatego będziemy modyfikować kod HTML lub stosować style ruchu tylko wtedy, gdy użytkownik zgadza się na ruch.

Poniżej znajdziesz ogólny opis przepływu pracy i wyników:

  1. Przygotuj zmienne warunkowe zmniejszonego ruchu dla CSS i JS.
  2. Przygotuj narzędzia do podziału tekstu w języku JavaScript.
  3. Uporządkuj warunki i narzędzia podczas wczytywania strony.
  4. Twórz przejścia i animacje CSS dla liter i słów (część rad).

Oto podgląd wyników warunkowych:

zrzut ekranu z narzędziami deweloperskimi w Chrome z otwartym panelem Elementy i zmniejszonym ruchem ustawionym na „reduce” (redukcja), a film h1 jest widoczny bez podziału
Użytkownik woli mniejszy ruch: tekst jest czytelny lub nierozdzielony

Jeśli użytkownik woli ruch z ograniczonym ruchem, pozostawiamy dokument HTML bez zmian i nie stosujemy animacji. Jeśli ruch jest w porządku, tniemy obraz na kawałki. Oto podgląd kodu HTML po tym, jak JavaScript podzieli tekst według liter.

zrzut ekranu z narzędziami deweloperskimi w Chrome z otwartym panelem Elementy i zmniejszonym ruchem ustawionym na „reduce” (redukcja), a film h1 jest widoczny bez podziału
Użytkownik nie ma problemów z ruchem; tekst podzielony na wiele elementów <span>

Przygotowywanie warunków dotyczących ruchu

W tym projekcie używane będzie dostępne zapytanie o media @media (prefers-reduced-motion: reduce) z zasobów CSS i JavaScript. To zapytanie o media to nasz główny warunek decyzji o rozdzieleniu tekstu. Zapytanie o media CSS będzie używane do pomijania przejść i animacji, a zapytanie o media JavaScript – do pominięcia manipulacji HTML.

Przygotowywanie warunku CSS

Udało mi się użyć narzędzia PostCSS, aby włączyć składnię zapytań o multimedia na poziomie 5, w której mogę zapisać wartość logiczną zapytania o media w zmiennej:

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

Przygotowywanie warunku JS

W kodzie JavaScript przeglądarka umożliwia sprawdzanie zapytań o multimedia. Za pomocą zniszczenia wyodrębniłam wynik logiczny z testu zapytania o multimedia i zmieniłam jego nazwę:

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

Mogę następnie przetestować działanie funkcji motionOK i zmienić dokument tylko wtedy, gdy użytkownik nie poprosił o zmniejszenie ruchu.

if (motionOK) {
  // document split manipulations
}

Mogę sprawdzić tę samą wartość za pomocą PostCSS i włączyć składnię @nest w Nesting Draft 1. Dzięki temu mogę w jednym miejscu przechowywać wszystkie logiki animacji i wymagania dotyczące jej stylu w odniesieniu do elementów nadrzędnych i podrzędnych:

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

Używając niestandardowej właściwości PostCSS i wartości logicznej JavaScript, możemy warunkowo uaktualnić efekt. Teraz przechodzimy do kolejnej sekcji, w której omawiam kod JavaScriptu służący do przekształcania ciągów znaków w elementy.

Dzielenie tekstu

Litery tekstowe, słowa, wiersze itp. nie mogą być animowane oddzielnie za pomocą CSS lub JS. Aby uzyskać ten efekt, potrzebne są pudełka. Jeśli chcemy animować każdą literę, każda z nich musi być elementem. Jeśli chcemy animować każde słowo, każde słowo musi być elementem.

  1. Utwórz funkcje narzędziowe JavaScript do dzielenia ciągów znaków na elementy
  2. Administrowanie korzystaniem z tych narzędzi

Funkcja podziału liter

Najlepiej zacząć od funkcji, która pobiera ciąg znaków i zwraca każdą literę w tablicy.

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

Rozpowszechnianie treści z ES6 bardzo pomogło sprawnie wykonać to zadanie.

Funkcja dzielenia słów

Podobnie jak w przypadku dzielenia liter, funkcja ta pobiera ciąg znaków i zwraca każde słowo w tablicy.

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

Metoda split() w ciągach tekstowych JavaScript pozwala nam określać, które znaki zostaną wycięte. Podana przeze mnie pusta spacja oznacza rozdzielenie słów.

Funkcja tworzenia pól wyboru

W efekcie każda litera musi mieć ramkę. W tych funkcjach widzimy, że funkcja map() jest wywoływana za pomocą funkcji span(). Oto funkcja span().

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

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

  return node
}

Pamiętaj, że właściwość niestandardowa o nazwie --index jest ustawiana na podstawie pozycji tablicy. Choć pola z animacjami liter są przydatne, ale dodanie indeksu do użycia w CSS to pozornie mały dodatek o dużym wpływie. Najbardziej charakterystyczne w przypadku tych efektów jest oszałamiające. Będziemy mogli użyć atrybutu --index jako sposobu kompensowania animacji i zwiększenia jej rozłożenia.

Wnioski dotyczące narzędzi

Ukończony moduł splitting.js:

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)

Następnym krokiem jest importowanie i używanie tych funkcji byLetter() i byWord().

Podział administracji

Gdy narzędzia do podziału są gotowe do użycia, połączenie wszystkich elementów w jedną całość oznacza:

  1. Znajdowanie elementów do podziału.
  2. Dzielenie ich i zastępowanie ich tekstem HTML.

Następnie kod CSS przejmuje elementy / pola i uruchamia ich animację.

Znajdowanie elementów

Do przechowywania informacji o pożądanej animacji i sposobu podziału tekstu używam atrybutów i wartości. Podobało mi się umieszczanie tych deklaratywnej opcji w kodzie HTML. Atrybut split-by jest używany z JavaScriptu do znajdowania elementów i tworzenia pól z literami lub słowami. Atrybut letter-animation lub word-animation jest używany z CSS do kierowania elementów podrzędnych oraz stosowania przekształceń i animacji.

Oto przykładowy kod HTML, który przedstawia te 2 atrybuty:

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

Znajdowanie elementów z JavaScriptu

Użyłem składni selektora arkusza CSS do określania obecności atrybutu, aby zebrać listę elementów, w których ma zostać podzielony tekst:

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

Znajdowanie elementów z CSS

Użyłem też selektora obecności atrybutu w CSS, aby nadać wszystkim animacji liter ten sam styl podstawowy. Później użyjemy wartości atrybutu, by dodać bardziej szczegółowe style w celu osiągnięcia odpowiedniego efektu.

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

Dzielę tekst w odpowiednim miejscu

W przypadku każdego podzielonego elementu docelowego zapisanego w kodzie JavaScript podzielimy ich tekst na podstawie wartości atrybutu i zmapujemy każdy ciąg na element <span>. Możemy wtedy zastąpić tekst utworzonymi polami:

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

Podsumowanie konfiguracji

Ukończono index.js:

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

Kod JavaScript można odczytać w tym języku:

  1. Zaimportuj niektóre pomocnicze funkcje narzędziowe.
  2. Sprawdź, czy ruch jest odpowiedni dla tego użytkownika. Jeśli nie, nic nie rób.
  3. Dla każdego elementu, który chcesz podzielić.
    1. Podziel je w zależności od tego, jak chcesz je podzielić.
    2. Zastąp tekst elementami.

Dzielenie animacji i przejść

W ten sposób udało Ci się wydobyć mnóstwo potencjalnych animacji i efektów za pomocą CSS lub JavaScriptu. Na końcu tego artykułu znajdziesz kilka linków, które pomogą Ci w podjęciu decyzji.

Czas pokazać, na co Cię stać. Udostępnię 4 animacje i przejścia oparte na CSS. 🤓

Podziel litery

Jako podstawę do stosowania efektów podziału liter przydatny był poniższy arkusz CSS. Wszystkie przejścia i animacje umieszczam za zapytaniem o media ruchu, a każdą nową literę podrzędną span nadaję właściwości wyświetlania i stylu, co oznacza, że odstępy mają być używane:

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

Styl spacji jest ważny, by rozpiętości, które są tylko spacjami, nie zostały zwinięte przez mechanizm układu. Przejdźmy do stanowych fajnych rzeczy.

Przykład podziału liter w punkcie przejścia

W tym przykładzie zastosowano przejścia CSS do efektu podzielonego tekstu. W przypadku przejść musimy określić, czy silnik będzie animował się między nimi. Wybrałem 3 stany: bez najechania kursorem, najedź kursorem w zdaniu, na literę.

Gdy użytkownik najedzie kursorem na zdanie (czyli kontener), odskaluję wszystkie elementy podrzędne tak, jakby użytkownik je odsunął. Następnie, gdy użytkownik najeżdża na literę, wyświetlam ją dalej.

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

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

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

Animuj przykład rozdzielonych liter

W tym przykładzie użyto wstępnie zdefiniowanej animacji @keyframe, aby każdą literę animować w nieskończoność, oraz wykorzystano wbudowany indeks właściwości niestandardowych do utworzenia efektu przesunięcia.

@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;
  }
}

Podziel słowa

W tych przykładach jako typ kontenera sprawdził się Flexbox, wykorzystując jednostkę ch jako typ kontenera o odpowiedniej długości.

word-animation {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1ch;
}
Narzędzia deweloperskie Flexbox pokazujące odstępy między słowami

Przykład dzielenia słów przejścia

W tym przykładzie przejścia ponownie użyję najechania kursorem. Efekt początkowo ukrywa treść do momentu najechania, więc upewniłem się, że interakcja i style są stosowane tylko wtedy, gdy urządzenie umożliwia najechanie kursorem.

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

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

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

Animacja przedstawiająca przykład dzielenia słów

W tym przykładzie animacji ponownie używam CSS @keyframes, aby utworzyć nieskończoną animację w zwykłym akapicie tekstu.

[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;
  }
}

Podsumowanie

Skoro już wiesz, jak to udało mi się osiągnąć, to jak? 🙂

Stwórzmy różne metody i nauczmy się wszystkiego, jak rozwijać się w internecie. Utwórz program Codepen lub udostępnij własną prezentację i prześlij mi go na tweeta, a dodam ją do sekcji remiksów ze społeczności poniżej.

Źródło

Więcej prezentacji i inspiracji

Remiksy społeczności