Tworzenie animacji podzielonego tekstu

Podstawowe omówienie tworzenia animacji liter i słów.

W tym poście chcę podzielić się z Wami sposobami na tworzenie animowanych tekstów i interakcji w internecie, które są minimalne, dostępne i działają we wszystkich przeglądarkach. Wypróbuj wersję demonstracyjną.

Demonstracja

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

Omówienie

Animacje tekstu podzielonego mogą być niesamowite. W tym poście przedstawimy tylko ułamek potencjału animacji, ale pozwoli on Ci zbudować solidne podstawy. Celem jest animacja stopniowa. Domyślnie tekst powinien być czytelny, a animacja powinna być na nim umieszczona. Efekty animacji tekstu mogą być ekstrawaganckie i potencjalnie uciążliwe, dlatego będziemy manipulować tylko HTML-em lub stosować style animacji, jeśli użytkownik wyrazi na to zgodę.

Oto ogólne omówienie procesu i jego wyników:

  1. Przygotuj zmienne warunkowe z ograniczonym ruchem dla plików CSS i JS.
  2. Przygotuj narzędzia do dzielenia tekstu w JavaScript.
  3. Zorganizuj warunki i elementy pomocnicze podczas wczytywania strony.
  4. Napisz przejścia i animacje CSS dla liter i słów (to najlepsza część).

Oto podgląd wyników warunkowych, które chcemy uzyskać:

zrzut ekranu z Narzędziami deweloperskimi Chrome z otwartą sekcją Elementy i ustawieniem ograniczonego ruchu na „reduce” (ogranicz ruch). Element h1 nie jest podzielony
Użytkownik preferuje ograniczenie ruchu: tekst jest czytelny i niepodzielony

Jeśli użytkownik woli ograniczone ruchy, nie zmieniamy dokumentu HTML i nie animujemy go. Jeśli ruch jest OK, dzielimy go na części. Oto podgląd kodu HTML po podzieleniu tekstu na litery za pomocą kodu JavaScript.

Zrzut ekranu przedstawiający narzędzia deweloperskie w Chrome z otwartym panelem Elements i zmniejszonym ruchem ustawionym na „reduce” (redukcja), a ekran h1 nie był podzielony.
Użytkownik zachowuje się zgodnie z ruchem; tekst podzielony na kilka elementów <span>

Przygotowywanie warunków ruchowych

W tym projekcie zapytanie o multimedia @media (prefers-reduced-motion: reduce) będzie używane z CSS i JavaScriptu. To zapytanie o multimedia jest naszym głównym warunkiem warunkowym, który decyduje o tym, czy tekst ma zostać podzielony. Zapytanie o media CSS będzie używane do blokowania przejść i animacji, a zapytanie o media JavaScript – do wstrzymania manipulacji HTML.

Przygotowywanie reguły usługi porównywania cen

Użyłem PostCSS, aby włączyć składnię zapytań o media na poziomie 5, gdzie mogę zapisać wartość logiczną zapytania o media w zmiennej:

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

Przygotowywanie warunku JS

W JavaScript przeglądarka udostępnia sposób sprawdzania zapytań medialnych. Aby wyodrębnić i zmienić nazwę wyniku logicznego z zapytania medialnego, użyłem destrukturyzacji:

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

Następnie mogę przetestować motionOK i zmienić dokument tylko wtedy, gdy użytkownik nie poprosił o zmniejszenie ruchu.

if (motionOK) {
  // document split manipulations
}

Mogę sprawdzić tę samą wartość, używając PostCSS do włączenia składni @nest z Nesting Draft 1. Dzięki temu mogę zapisać w jednym miejscu całą logikę animacji i jej wymagania dotyczące stylu dotyczące elementów nadrzędnych i podrzędnych:

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

Dzięki właściwości niestandardowej PostCSS i wartości logicznej JavaScript możemy warunkowo uaktualniać efekt. W następnej sekcji omówię kod JavaScript służący do przekształcania ciągów tekstowych w elementy.

Dzielenie tekstu

Litery, słowa, linie tekstu itp. nie mogą być animowane za pomocą CSS ani JS. Aby uzyskać ten efekt, potrzebujemy pudełek. Jeśli chcemy animować każdą literę, każda litera musi być elementem. Jeśli chcemy animować każde słowo, każde słowo musi być elementem.

  1. Tworzenie funkcji pomocniczych JavaScript do dzielenia ciągów znaków na elementy
  2. sterować korzystaniem z tych narzędzi;

Funkcja dzielenia liter

Ciekawym punktem wyjścia jest funkcja, która przyjmuje ciąg znaków i zwraca każdy znak w tablicy.

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

Dzięki składni spread z ES6 udało mi się to zrobić bardzo szybko.

Funkcja użytkowa dzielenia słów

Podobnie jak w przypadku dzielenia liter, ta funkcja przyjmuje ciąg znaków i zwraca każdy wyraz w tablicy.

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

Metoda split() w przypadku ciągów znaków JavaScriptu umożliwia nam określenie, na których znakach ma być wykonywany podział. Przeszedłem przez pustą przestrzeń, co wskazuje na podział między słowami.

Funkcja narzędziowa skrzynek

Efekt wymaga umieszczenia ramki na każdą literę. 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 przypadku właściwości niestandardowej o nazwie --index jest ustawiana pozycja tablicy. Pole z animowanymi literami to świetna rzecz, ale indeks do użycia w CSS to pozornie małe uzupełnienie, które ma duży wpływ. Najbardziej zauważalny w tym przypadku jest rozkład czasu. Będziemy mogli użyć elementu --index, aby zrównoważyć animacje w celu rozłożenia animacji.

Wnioski dotyczące narzędzi

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ępnie importujesz i używasz funkcji byLetter()byWord().

Administracja podziałem

Po przygotowaniu narzędzi do dzielenia plików możesz je połączyć w ten sposób:

  1. Wybieranie elementów do podzielenia
  2. Podziel je i zastąp tekst kodem HTML.

Następnie CSS przejmuje kontrolę i animuje elementy / pola.

Wyszukiwanie elementów

Wykorzystałem atrybuty i wartości do przechowywania informacji o wybranej animacji i sposobu podziału tekstu. Spodobało mi się umieszczanie tych opcji deklaratywnych w kodzie HTML. Atrybut split-by jest używany w JavaScripcie do znajdowania elementów i tworzenia pól dla liter lub słów. Atrybut letter-animation lub word-animation jest używany w CSS do kierowania na elementy potomne i stosowania przekształceń oraz animacji.

Oto przykładowy kod HTML, który demonstruje 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 w JavaScript

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

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

Znajdowanie elementów z CSS

Użyłem też w CSS selektora obecności atrybutu, aby nadać wszystkim animacjom liter tym samym stylom podstawowym. Później użyjemy wartości atrybutu, aby dodać bardziej szczegółowe style, które pomogą uzyskać pożądany efekt.

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

Dzielenie tekstu na miejscu

W przypadku każdego podzielonego celu w języku JavaScript podzielimy tekst na podstawie wartości atrybutu i zmapujemy każdy ciąg na obiekt <span>. Następnie możemy zastąpić tekst elementu utworzonymi przez nas 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 administracji

index.js ukończone:

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

Fragment kodu JavaScript można odczytać w języku angielskim:

  1. importować niektóre pomocnicze funkcje pomocnicze.
  2. Sprawdź, czy ruch jest ok dla tego użytkownika, jeśli nie, nic nie rób.
  3. W przypadku każdego elementu, który chcesz podzielić.
    1. podzielić je na podstawie tego, jak użytkownicy chcą je podzielić.
    2. Zastępowanie tekstu elementami.

Dzielenie animacji i przejść

Powyższa manipulacja dokumentem odblokowała wiele potencjalnych animacji i efektów za pomocą CSS lub JavaScriptu. Na końcu tego artykułu podajemy kilka linków, które mogą Cię zainspirować.

Czas na pokazanie, co możesz zrobić z tą funkcją. Pokażę 4 animacje i przejścia oparte na CSS. 🤓

Dzielenie liter

Jako podstawę efektów litery podzielonej na części wykorzystałem następujący kod CSS. Wszystkie przejścia i animacje umieszczam w zapytaniu dotyczącego mediów animowanych, a następnie każdemu nowemu podrzędnemu elementowi span przypisuję właściwość wyświetlania oraz styl dotyczący białych przestrzeni:

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

Styl białych spacji jest ważny, aby elementy, które są tylko spacją, nie były zwijane przez mechanizm układu. Teraz o ciekawostkach związanych ze stanem.

Przykład litery z podzieleniem na części

W tym przykładzie przejścia CSS są używane do efektu podzielonego tekstu. Przejścia wymagają określonych stanów, między którymi animuje się mechanizm. Wybrałem 3 stany: brak najechania, najechanie kursorem, najechanie kursorem na literę.

Gdy użytkownik najedzie kursorem na zdanie, czyli kontener, zmniejszam wszystkie elementy podrzędne, tak jakby użytkownik przesunął je dalej. Gdy użytkownik najedzie na literę, wysuwam ją do przodu.

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

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

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

Przykład animowania podzielonych liter

W tym przykładzie do nieskończonej animacji każdego znaku używana jest wstępnie zdefiniowana animacja @keyframe, a do tworzenia efektu przesunięcia wykorzystywany jest indeks właściwości niestandardowych w ramce.

@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 na słowa

Flexbox w tych przykładach sprawdza się jako rodzaj kontenera – dobrze wykorzystano w nim jednostkę ch, która zapewnia odpowiednią długość luki.

word-animation {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1ch;
}
Flexbox devtools pokazujący odstęp między słowami

Przykład dzielenia słów w tłumaczeniu

W tym przykładzie przejścia używam ponownie kursora. Początkowo efekt ukrywania treści do momentu najechania kursorem sprawiał, że interakcje i style były stosowane tylko wtedy, gdy urządzenie mogło najechać kursorem.

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

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

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

Przykład animacji dzielenia słów

W tym przykładzie animacji ponownie używam CSS @keyframes, aby utworzyć stopniowo przechodzącą animację nieskończoną na 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

Teraz, gdy już wiesz, jak to zrobić, jak Ty to zrobisz? 🙂

Zróżnicujemy nasze podejścia i poznamy wszystkie sposoby tworzenia stron internetowych. Utwórz Codepen lub opublikuj własne demo, tweetuj je, a ja dodam je do sekcji Remixe społeczności poniżej.

Źródło

Więcej wersji demonstracyjnych i inspiracji

Remiksy utworzone przez społeczność