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 tylko spróbujemy liznąć potencjału animacji, ale już teraz możesz zacząć budować na tej podstawie. Celem jest animacja stopniowa. Tekst powinien być czytelny domyślnie, a animacja powinna być dodana na górze. 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 ograniczoną animację: tekst jest czytelny / nierozdzielony

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ą JavaScript.

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 akceptuje ruch; 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. Definicja media w CSS będzie używana do blokowania przejść i animacji, a definicja media w JavaScriptie do blokowania manipulacji HTML.

Przygotowywanie reguły usługi porównywania cen

Użyłem PostCSS, aby włączyć składnię zapytań multimedialnych na poziomie 5, w której mogę przechowywać zapytanie logiczne o multimediach 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, aby włączyć składnię @nest z wersji roboczej 1 tworzenia zagnieżdżonych reguł. Dzięki temu mogę przechowywać w jednym miejscu całą logikę animacji i wymagania dotyczące stylu dla 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 w JavaScript możemy warunkowo uaktualniać efekt. W następnej sekcji omówię kod JavaScript służący do przekształcania ciągów znaków w elementy.

Dzielenie tekstu

Liter, słów, wierszy itp. nie można animować indywidualnie 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 pomocnicza 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 poszczególne słowa 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 oznacza podział między słowami.

Funkcja narzędziowa skrzynek

Efekt wymaga pól dla każdej litery, a 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żywać --index do przesuwania animacji w celu uzyskania efektu przesunięcia.

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().

Podział administracji

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 usługa porównywania cen przejmie kontrolę i animuje elementy lub pola.

Wyszukiwanie elementów

Użyłam atrybutów i wartości, aby przechowywać informacje o pożądanej animacji i sposobie podziału tekstu. Spodobało mi się umieszczanie tych opcji deklaratywnych w kodzie HTML. Atrybut split-by jest używany w JavaScript do znajdowania elementów i tworzenia pól dla liter lub słów. Atrybut letter-animation lub word-animation jest używany w kodzie 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 w pliku CSS

Użyłam też selektora obecności atrybutu w CSS, 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 z wykrytych w JavaScriptie celów podziału tekst zostanie podzielony na podstawie wartości atrybutu, a każdy ciąg znaków zostanie mapowany na <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 administrowania

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

Kod JavaScript może wyglądać tak:

  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 dzielić.
    2. Zastępowanie tekstu elementami.

Dzielenie animacji i przejść

Powyższe manipulowanie dokumentem w celu jego podzielenia umożliwia tworzenie wielu potencjalnych animacji i efektów za pomocą CSS lub JavaScriptu. Na końcu tego artykułu znajdziesz kilka linków do materiałów, które pomogą Ci w tym zakresie.

Czas na pokazanie, co możesz z nim zrobić. 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, który określa, co ma się stać z białymi przestrzeniami:

[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 przejściowym podziałem na litery

W tym przykładzie przejścia CSS są używane do efektu podzielonego tekstu. W przypadku przejść potrzebujemy stanów, które silnik będzie animował. Wybrałem 3 stany: bez najechania, najechanie w zdaniu i najechanie na literę.

Gdy użytkownik najedzie kursorem na zdanie, czyli na 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żywa się zdefiniowanej wstępnie animacji @keyframe, a do tworzenia efektu przesunięcia wykorzystuje się 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

W tych przykładach Flexbox działał jako typ kontenera, wykorzystując jednostkę ch jako odpowiednią długość przerwy.

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. Ponieważ efekt początkowo ukrywa zawartość, aż do momentu najechania na nią kursorem, upewniłam się, że interakcja i style są stosowane tylko wtedy, gdy urządzenie ma możliwość najechania kursorem.

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

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

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

Przykład animowania podzielonych 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 prześlij 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 społeczności