Una panoramica di base su come creare animazioni di lettere e parole divise.
In questo post voglio condividere alcune idee su come risolvere le animazioni e le interazioni del testo diviso per il web in modo che siano minimali, accessibili e funzionino su tutti i browser. Prova la demo.
Se preferisci i video, ecco una versione di questo post su YouTube:
Panoramica
Le animazioni di testo divise possono essere straordinarie. In questo post toccheremo appena la superficie del potenziale dell'animazione, ma forniamo una base su cui costruire. L'obiettivo è animare progressivamente. Il testo deve essere leggibile per impostazione predefinita, con l'animazione sopra. Gli effetti di movimento del testo diviso possono essere esagerati e potenzialmente disgreganti, pertanto manipoleremo solo l'HTML o applicheremo stili di movimento se l'utente accetta il movimento.
Ecco una panoramica generale del flusso di lavoro e dei risultati:
- Prepara le variabili condizionali per il movimento ridotto per CSS e JS.
- Prepara le utilità per il testo suddiviso in JavaScript.
- Orchestra le espressioni condizionali e le utilità al caricamento della pagina.
- Scrivi transizioni e animazioni CSS per lettere e parole (la parte più interessante).
Ecco un'anteprima dei risultati condizionali che intendiamo ottenere:
Se un utente preferisce ridurre il movimento, lasciamo invariato il documento HTML e non viene eseguita alcuna animazione. Se il movimento è OK, procediamo e lo dividiamo in pezzi. Ecco un'anteprima del codice HTML dopo che JavaScript ha suddiviso il testo per lettera.
Preparazione delle condizioni di movimento
La query sui contenuti multimediali @media
(prefers-reduced-motion: reduce)
, disponibile, verrà utilizzata da CSS e
JavaScript in questo progetto. Questa query sui media è la nostra condizione principale per decidere se suddividere o meno il testo. La query sui media CSS verrà utilizzata per nascondere le transizioni e le animazioni, mentre la query sui media JavaScript verrà utilizzata per nascondere la manipolazione HTML.
Preparazione del CSS condizionale
Ho utilizzato PostCSS per attivare la sintassi del Livello 5 delle query supporti, in cui posso memorizzare una query booleana in una variabile:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
Preparazione dell'istruzione condizionale JS
In JavaScript, il browser fornisce un modo per controllare le query sui media. Ho utilizzato la destrutturazione per estrarre e rinominare il risultato booleano dal controllo delle query sui media:
const {matches:motionOK} = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
)
Posso quindi verificare la presenza di 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
di
Nesting Draft 1. In questo modo posso memorizzare tutta la logica dell'animazione e i relativi requisiti di stile per gli elementi principali e secondari in un'unica posizione:
letter-animation {
@media (--motionOK) {
/* animation styles */
}
}
Con la proprietà personalizzata PostCSS e un booleano JavaScript, siamo pronti per eseguire l'upgrade dell'effetto in modo condizionale. Passiamo alla sezione successiva, dove analizzerò il codice JavaScript per la trasformazione delle stringhe in elementi.
Suddivisione del testo
Le lettere, le parole, le righe di testo e così via non possono essere animate singolarmente con CSS o JS. Per ottenere l'effetto, abbiamo bisogno di caselle. Se vogliamo animare ogni lettera, ogni lettera deve essere un elemento. Se vogliamo animare ogni parola, ogni parola deve essere un elemento.
- Creare funzioni di utilità JavaScript per suddividere le stringhe in elementi
- Orchestrare l'utilizzo di queste utilità
Funzione di utilità per la suddivisione delle lettere
Un buon punto di partenza è una funzione che prende una stringa e restituisce ogni lettera in un array.
export const byLetter = text =>
[...text].map(span)
La sintassi di spread di ES6 ha contribuito a semplificare notevolmente l'operazione.
Funzione di utilità per la 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 in base ai quali eseguire l'operazione di slicing.
Ho passato uno spazio vuoto, che indica una separazione tra le parole.
Creazione di una funzione di utilità per le caselle
L'effetto richiede caselle per ogni lettera e in queste funzioni vediamo che
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 delle lettere è fantastico, ma avere un indice da utilizzare in CSS è un'aggiunta apparentemente piccola con un grande impatto.
La caratteristica più evidente di questo impatto elevato è la stagionalità.
Potremo utilizzare --index
per compensare le animazioni per un effetto sfasato.
Conclusione: utilità
Il modulo splitting.js
in fase di completamento:
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)
A questo punto, devi importare e utilizzare queste funzioni byLetter()
e byWord()
.
Suddividi orchestrazione
Con gli strumenti di suddivisione pronti per l'uso, mettere tutto insieme significa:
- Trovare gli elementi da suddividere
- Suddividendo e sostituendo il testo con HTML
Dopodiché, il CSS prende il controllo e anima gli elementi / le caselle.
Trovare elementi
Ho scelto di utilizzare attributi e valori per memorizzare le informazioni sull'animazione e su come suddividere il testo. Mi è piaciuto inserire queste opzioni declarative
in 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 figli e applicare trasformazioni e animazioni.
Ecco un esempio di codice HTML che mostra 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 di attributi per raccogliere l'elenco degli elementi di cui si vuole suddividere il testo:
const splitTargets = document.querySelectorAll('[split-by]')
Trovare elementi da CSS
Ho anche utilizzato il selettore di presenza dell'attributo in CSS per assegnare a tutte le animazioni delle lettere gli stessi stili di base. In seguito, utilizzeremo il valore dell'attributo per aggiungere stili più specifici per ottenere un effetto.
letter-animation {
@media (--motionOK) {
/* animation styles */
}
}
Suddivisione del testo in blocco
Per ogni target di suddivisione che troviamo in JavaScript, suddividiamo il testo in base al valore dell'attributo e mappiamo ogni stringa a un <span>
. Possiamo quindi sostituire il testo dell'elemento con le caselle che abbiamo creato:
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
in fase di completamento:
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 testo in inglese:
- Importa alcune funzioni di utilità di supporto.
- Controlla se il movimento è OK per questo utente, altrimenti non fare nulla.
- Per ogni elemento da suddividere.
- Suddividerli in base a come vogliono essere suddivisi.
- Sostituisci il testo con elementi.
Suddividere animazioni e transizioni
La manipolazione del documento di suddivisione sopra descritta ha appena sbloccato una moltitudine di potenziali animazioni ed effetti con CSS o JavaScript. Di seguito sono riportati alcuni link per aiutarti a trovare idee per la suddivisione.
È arrivato il momento di mostrare cosa puoi fare con questa funzionalità. Condividerò 4 animazioni e transizioni basate su CSS. 🤓
Lettere separate
Come base per gli effetti di lettere divise, ho trovato utile il seguente CSS. Inserisco tutte le transizioni e le animazioni dietro la query sui contenuti multimediali in movimento e poi associo a ogni nuova lettera secondaria span
una proprietà di visualizzazione e uno stile per le operazioni da eseguire sugli spazi bianchi:
[letter-animation] > span {
display: inline-block;
white-space: break-spaces;
}
Lo stile degli spazi bianchi è importante affinché gli spazi costituiti solo da uno spazio non vengano compressi dal motore di layout. Ora passiamo alle cose divertenti con stato.
Esempio di lettere con suddivisione delle transizioni
Questo esempio utilizza le transizioni CSS per l'effetto di testo diviso. Con le transizioni abbiamo bisogno di stati tra cui il motore può eseguire l'animazione e ho scelto 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 contenitore, riduco tutte le figlie come se l'utente le avesse allontanate. Poi, quando l'utente passa il mouse sopra una lettera, la faccio avanzare.
@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 infinitamente ogni lettera e sfrutta l'indice della proprietà personalizzata in linea per creare un effetto di sfasamento.
@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
In questi esempi, Flexbox ha funzionato come tipo di contenitore, sfruttando in modo efficace l'unità ch
come lunghezza ottimale per gli spazi.
word-animation {
display: inline-flex;
flex-wrap: wrap;
gap: 1ch;
}
Esempio di parole divise per transizione
In questo esempio di transizione utilizzo di nuovo il passaggio del mouse. Poiché l'effetto nasconde inizialmente i contenuti fino al passaggio del mouse, ho fatto in modo che l'interazione e gli stili venissero applicati solo se il dispositivo aveva la possibilità di eseguire il passaggio del mouse.
@media (hover) {
[word-animation="hover"] {
overflow: hidden;
overflow: clip;
& > span {
transition: transform .3s ease;
cursor: pointer;
&:not(:hover) {
transform: translateY(50%);
}
}
}
}
Esempio di animazione delle parole divise
In questo esempio di animazione, utilizzo di nuovo il CSS @keyframes
per creare un'animazione infinita alternata 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 ho fatto, come faresti? 🙂
Diversifichiamo i nostri approcci e impariamo tutti i modi per creare sul web. Crea un Codepen o ospita la tua demo, inviami un tweet e la aggiungerò alla sezione Remix della community di seguito.
Origine
Altre demo e ispirazione
Remix della community
- Componente web
<text-hover>
di gnehcwu su CodeSandbox