Creare animazioni di testo diviso

Una panoramica di base su come creare animazioni di lettere divise e parole.

In questo post voglio condividere idee su come risolvere animazioni e interazioni di testo diviso per il web che siano minime, accessibili e funzionino su tutti i browser. Prova la demo.

Demo

Se preferisci i video, ecco una versione di YouTube di questo post:

Panoramica

Le animazioni con testo diviso possono essere sorprendenti. In questo post riusciremo a malapena a tracciare la superficie del potenziale animato, ma fornisce una base su cui sviluppare. L'obiettivo è un'animazione progressiva. Il testo deve essere leggibile per impostazione predefinita, con l'animazione integrata. Gli effetti di movimento del testo suddivisi possono diventare stravaganti e potenzialmente fastidiosi, quindi manipoleremo solo l'HTML o applicheremo stili di movimento se l'utente è d'accordo con il movimento.

Ecco una panoramica generale del flusso di lavoro e dei risultati:

  1. Prepara le variabili condizionali di movimento ridotte per CSS e JS.
  2. Prepara le utilità di suddivisione del testo in JavaScript.
  3. Orchestra le condizioni e le utilità al caricamento della pagina.
  4. Scrivi transizioni e animazioni CSS per lettere e parole (la parte rad!).

Ecco un'anteprima dei risultati condizionali a cui faremo riferimento:

Screenshot di Chrome DevTools con il riquadro Elementi aperto e il movimento ridotto impostato su "Riduzione" e il simbolo h1 mostrato non diviso
L'utente preferisce il movimento ridotto: il testo è leggibile / non diviso

Se un utente preferisce un movimento ridotto, lasciamo solo il documento HTML e non facciamo animazioni. Se il movimento è OK, procediamo a spezzarlo in fette. Ecco un'anteprima del codice HTML dopo che JavaScript ha suddiviso il testo per lettera.

Screenshot di Chrome DevTools con il riquadro Elementi aperto e il movimento ridotto impostato su "Riduzione" e il simbolo h1 mostrato non diviso
L'utente supporta il movimento; testo suddiviso in più elementi <span>

Preparazione delle condizionali di movimento

La pratica query multimediale @media (prefers-reduced-motion: reduce) disponibile verrà utilizzata da CSS e JavaScript in questo progetto. Questa query supporti è la nostra condizione principale per decidere se dividere o meno il testo. La query multimediale CSS verrà utilizzata per trattenere transizioni e animazioni, mentre la query multimediale JavaScript verrà utilizzata per impedire la manipolazione HTML.

Preparazione del condizionale CSS

Ho utilizzato PostCSS per attivare la sintassi di Media Queries Level 5, in cui posso memorizzare una query multimediale booleana in una variabile:

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

Preparazione del condizionale JS

In JavaScript, il browser fornisce un modo per controllare le query supporti. Ho usato destructuring per estrarre e rinominare il risultato booleano dal controllo delle query supporti:

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

Posso quindi testare motionOK e modificare il documento solo se l'utente non ha richiesto di ridurre il movimento.

if (motionOK) {
  // document split manipulations
}

Posso controllare lo stesso valore utilizzando PostCSS per attivare la sintassi @nest dalla bozza Nesting 1. Ciò mi consente di archiviare in un'unica posizione tutte le logiche dell'animazione e i relativi requisiti di stile per gli elementi principali e secondari:

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

Con la proprietà personalizzata PostCSS e un valore booleano JavaScript, siamo pronti a eseguire l'upgrade condizionale dell'effetto. Passiamo alla sezione successiva, dove suddivido il codice JavaScript per trasformare le stringhe in elementi.

Suddivisione del testo

Le lettere di testo, le parole, le righe e così via non possono essere animate singolarmente con CSS o JS. Per ottenere l'effetto, abbiamo bisogno di scatole. Se vogliamo animare ogni lettera, ogni lettera deve essere un elemento. Se vogliamo animare ogni parola, ogni parola deve essere un elemento.

  1. Creare funzioni di utilità JavaScript per suddividere le stringhe in elementi
  2. Orchestra l'uso di queste utilità

Funzione di utilità per dividere le lettere

Un punto di inizio divertente è con una funzione che prende una stringa e restituisce ogni lettera di un array.

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

La sintassi spread di ES6 ha davvero contribuito a rendere questa operazione rapida.

Funzione di utilità di suddivisione delle parole

Analogamente alla suddivisione delle lettere, questa funzione prende una stringa e restituisce ogni parola in un array.

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

Il metodo split() sulle stringhe JavaScript ci consente di specificare i caratteri da suddividere. Ho superato uno spazio vuoto, che indica una divisione tra le parole.

Funzione di utilità delle scatole

L'effetto richiede caselle per ogni lettera e, come abbiamo notato, in queste funzioni map() viene chiamato con una funzione span(). Ecco la funzione span().

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

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

  return node
}

È fondamentale notare che viene impostata una proprietà personalizzata denominata --index con la posizione dell'array. Avere le caselle per le animazioni con le lettere è un'ottima cosa, ma avere un indice da utilizzare in CSS è un'aggiunta apparentemente piccola con un grande impatto. L'aspetto più notevole in questo grande impatto è sconcertante. Potremo utilizzare --index per compensare le animazioni per una visualizzazione sfalsata.

Conclusione dei servizi di pubblica utilità

Il modulo splitting.js è stato completato:

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)

Ora devi importare e utilizzare le funzioni byLetter() e byWord().

Orchestrazione suddivisa

Con le utility di suddivisione pronte per l'uso, combinare tutto questo significa che:

  1. Trovare gli elementi da suddividere
  2. Dividerli e sostituire il testo con HTML

Dopodiché, CSS prende in carico e anima gli elementi / le caselle.

Elementi dei risultati

Ho scelto di usare attributi e valori per memorizzare informazioni sull'animazione desiderata e su come suddividere il testo. Mi piaceva inserire queste opzioni dichiarative nel codice HTML. L'attributo split-by viene utilizzato da JavaScript per trovare elementi e creare caselle per lettere o parole. L'attributo letter-animation o word-animation viene utilizzato da CSS per scegliere come target gli elementi secondari e applicare trasformazioni e animazioni.

Di seguito è riportato un esempio di codice HTML che illustra i due attributi:

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

Trovare elementi da JavaScript

Ho utilizzato la sintassi del selettore CSS per la presenza degli attributi in modo da raccogliere l'elenco di elementi che vogliono la loro suddivisione del testo:

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

Trovare elementi da CSS

Ho anche usato il selettore della presenza di attributi in CSS per assegnare le animazioni a tutte le lettere gli stessi stili di base. In seguito utilizzeremo il valore dell'attributo per aggiungere stili più specifici e ottenere un effetto.

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

Suddivisione del testo in posizione

Per ogni target di suddivisione che troviamo in JavaScript, suddivideremo il testo in base al valore dell'attributo e mapperemo ogni stringa a un <span>. Possiamo quindi sostituire il testo dell'elemento con le caselle create:

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

Conclusione dell’orchestrazione

index.js completato:

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

Il codice JavaScript potrebbe essere letto nel seguente inglese:

  1. Importare alcune funzioni di utilità di supporto.
  2. Controlla se il movimento è consentito per l'utente; in caso contrario, non fare nulla.
  3. Per ogni elemento che vuoi dividere.
    1. Suddividili in base a come vuoi che vengano suddivisi.
    2. Sostituisci il testo con elementi.

Divisione di animazioni e transizioni

La suddetta manipolazione del documento con la suddivisione ha appena sbloccato una moltitudine di potenziali effetti ed animazioni con CSS o JavaScript. Alla fine di questo articolo, troverai alcuni link che ti aiuteranno a individuare il tuo potenziale di suddivisione.

È ora di dimostrare cosa sai fare. condividerò 4 animazioni e transizioni basate su CSS. 🤓

Lettere divise

Come base per gli effetti delle lettere divisa, ho trovato utile il seguente codice CSS. Inserisco tutte le transizioni e le animazioni dietro la query dei contenuti multimediali di movimento e assegno a ogni nuova lettera secondaria span una proprietà di visualizzazione e uno stile per cosa fare con gli spazi bianchi:

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

Lo stile degli spazi bianchi è importante per far sì che le sezioni che sono solo uno spazio non vengano compresse dal motore di layout. Passiamo ora alle cose divertenti stateful.

Esempio di lettere divise di transizione

Questo esempio utilizza le transizioni CSS per l'effetto di testo diviso. Nel caso delle transizioni, sono necessari degli stati affinché il motore si anima e scelgo tre stati: nessun passaggio del mouse, passaggio del mouse nella frase, passaggio del mouse su una lettera.

Quando l'utente passa il mouse sopra la frase, ovvero il container, riduco tutti i bambini come se l'utente li avesse spinti più lontano. Poi, quando l'utente passa il mouse sopra una lettera, la inserisco.

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

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

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

Esempio di animazione di lettere divise

Questo esempio utilizza un'animazione @keyframe predefinita per animare all'infinito ogni lettera e utilizza l'indice di proprietà personalizzate incorporate per creare un effetto sfalsato.

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

Dividi parole

Flexbox ha funzionato come tipo di container per me in questi esempi, sfruttando l'unità ch come lunghezza dello spazio vuoto.

word-animation {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1ch;
}
Strumenti per sviluppatori Flexbox che mostrano il divario tra le parole

Esempio di parole divise con transizione

In questo esempio di transizione uso di nuovo il mouse. Inizialmente l'effetto nasconde i contenuti fino al passaggio del mouse, pertanto mi sono assicurato che l'interazione e gli stili venissero applicati solo se il dispositivo aveva la possibilità di passare il mouse sopra.

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

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

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

Esempio di animazione di parole divise

In questo esempio di animazione utilizzo nuovamente CSS @keyframes per creare un'animazione infinita sfalsata su un normale paragrafo di testo.

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

Conclusione

Ora che sai come ci sono riuscito, come faresti?! 🙂

Diversifica i nostri approcci e scopriamo tutti i modi per creare sul web. Crea un Codepen o ospita la tua demo, inviami un tweet e lo aggiungerò alla sezione Remix della community qui sotto.

Origine

Altre demo e ispirazione

Remix della community