Una panoramica di base su come creare animazioni con 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 del testo diviso possono essere incredibili. 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 default, con l'animazione in primo piano. Gli effetti di movimento del testo divisi possono diventare stravaganti e potenzialmente fastidiosi, quindi manipoleremo il codice HTML o applicheremo stili di movimento solo se l'utente è d'accordo con 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.
- Preparare le utilità di testo diviso 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 abbiamo pensato:
Se un utente preferisce la riduzione del movimento, lasciamo solo il documento HTML e non verrà eseguita l'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 multimediale CSS verrà utilizzata per trattenere
transizioni e animazioni, mentre la query multimediale JavaScript verrà utilizzata per
trattenere la manipolazione HTML.
Preparazione del CSS condizionale
Ho utilizzato PostCSS per abilitare la sintassi delle query multimediali di livello 5, dove posso memorizzare un valore multimediale di 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 verificare lo stesso valore utilizzando PostCSS per attivare la sintassi @nest
da
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 scatole. 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
- Orchestra 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 aspetto sfalsato.
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()
.
Orchestrazione suddivisa
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 secondari 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]')
Ricerca di elementi da CSS
Ho anche utilizzato il selettore della presenza dell'attributo in CSS per applicare gli stessi stili di base a tutte le animazioni delle lettere. 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 sul posto
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 delle lettere divisa, 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. E ora passiamo alle cose divertenti e divertenti.
Esempio di combinazione di lettere di transizione
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 su una lettera, la porto in avanti.
@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 transizione di parole divise
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 di parole divise
In questo esempio di animazione, utilizzo di nuovo il CSS @keyframes
per creare un'animazione infinita con spaziatura 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 ho fatto, come lo faresti?! 🙂
Diversificaamo i nostri approcci e impariamo tutti i modi per creare sul web. Crea un codepen o ospita la tua demo, twittami e lo aggiungerò alla sezione Remix della community qui sotto.
Origine
Altre demo e ispirazione
Remix della community
- Componente web
<text-hover>
di gnehcwu su CodeSandbox