Descripción general básica de cómo crear animaciones de letras y palabras divididas.
En esta entrada, quiero compartir ideas sobre cómo resolver animaciones e interacciones de texto dividido para la Web que sean mínimas, accesibles y funcionen en todos los navegadores. Prueba la demostración.
Si prefieres un video, aquí tienes una versión de este artículo en YouTube:
Descripción general
Las animaciones de texto dividido pueden ser increíbles. En esta publicación, apenas exploraremos el potencial de la animación, pero sí proporcionaremos una base para desarrollarla. El objetivo es animar de forma progresiva. El texto debe ser legible de forma predeterminada, con la animación superpuesta. Los efectos de movimiento de texto dividido pueden ser extravagantes y potencialmente disruptivos, por lo que solo manipularemos HTML o aplicaremos estilos de movimiento si el usuario acepta el movimiento.
A continuación, se incluye una descripción general del flujo de trabajo y los resultados:
- Prepara variables condicionales de movimiento reducido para CSS y JS.
- Prepara utilidades de texto dividido en JavaScript.
- Organiza las condiciones y las utilidades en la carga de la página.
- Escribe transiciones y animaciones CSS para letras y palabras (¡la parte genial!).
Esta es una vista previa de los resultados condicionales que queremos obtener:

Si un usuario prefiere un movimiento reducido, dejamos el documento HTML tal como está y no realizamos ninguna animación. Si el movimiento es correcto, lo dividimos en partes. Aquí tienes una vista previa del código HTML después de que JavaScript dividió el texto por letras.

Cómo preparar las condiciones de movimiento
La consulta de medios disponible @media
(prefers-reduced-motion: reduce)
se usará desde CSS y JavaScript en este proyecto. Esta consulta de medios es nuestra principal condición para decidir si se divide el texto o no. La consulta de medios de CSS se usará para retener las transiciones y animaciones, mientras que la consulta de medios de JavaScript se usará para retener la manipulación de HTML.
Cómo preparar la condición CSS
Usé PostCSS para habilitar la sintaxis de Media Queries Level 5, donde puedo almacenar un valor booleano de consulta de medios en una variable:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
Cómo preparar la condición JS
En JavaScript, el navegador proporciona una forma de verificar las consultas de medios. Usé la desestructuración para extraer y cambiar el nombre del resultado booleano de la verificación de la consulta de medios:
const {matches:motionOK} = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
)
Luego, puedo probar motionOK
y solo cambiar el documento si el usuario no solicitó reducir el movimiento.
if (motionOK) {
// document split manipulations
}
Puedo verificar el mismo valor con PostCSS para habilitar la sintaxis @nest
de Nesting Draft 1. Esto me permite almacenar toda la lógica sobre la animación y sus requisitos de estilo para el elemento principal y los secundarios en un solo lugar:
letter-animation {
@media (--motionOK) {
/* animation styles */
}
}
Con la propiedad personalizada de PostCSS y un valor booleano de JavaScript, ya podemos actualizar el efecto de forma condicional. Esto nos lleva a la siguiente sección, en la que desgloso el código JavaScript para transformar cadenas en elementos.
Cómo dividir texto
Las letras, las palabras, las líneas, etc., de texto no se pueden animar individualmente con CSS o JS. Para lograr el efecto, necesitamos cajas. Si queremos animar cada letra, cada una debe ser un elemento. Si queremos animar cada palabra, cada una debe ser un elemento.
- Crea funciones de utilidad de JavaScript para dividir cadenas en elementos
- Orquesta el uso de estas utilidades
Función de utilidad para dividir letras
Un buen punto de partida es una función que toma una cadena y devuelve cada letra en un array.
export const byLetter = text =>
[...text].map(span)
La sintaxis de propagación de ES6 ayudó mucho a que esa tarea fuera rápida.
Función de utilidad para dividir palabras
Al igual que con la división de letras, esta función toma una cadena y devuelve cada palabra en un array.
export const byWord = text =>
text.split(' ').map(span)
El método split()
en cadenas de JavaScript nos permite especificar en qué caracteres cortar.
Pasé un espacio vacío, lo que indica una división entre palabras.
Función de utilidad para crear cajas
El efecto requiere casillas para cada letra, y vemos en esas funciones que se llama a map()
con una función span()
. Esta es la función span()
.
const span = (text, index) => {
const node = document.createElement('span')
node.textContent = text
node.style.setProperty('--index', index)
return node
}
Es fundamental tener en cuenta que se está configurando una propiedad personalizada llamada --index
con la posición del array. Tener las casillas para las animaciones de letras es genial, pero tener un índice para usar en CSS es una adición aparentemente pequeña con un gran impacto.
Lo más notable de este gran impacto es su escalonamiento.
Podremos usar --index
como una forma de desplazar las animaciones para lograr un aspecto escalonado.
Conclusión de Utilidades
El módulo splitting.js
completado:
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 continuación, se importan y usan estas funciones byLetter()
y byWord()
.
Organización de divisiones
Con las utilidades de división listas para usar, juntar todo significa lo siguiente:
- Cómo encontrar qué elementos dividir
- Dividir y reemplazar texto con HTML
Después de eso, CSS se hace cargo y animará los elementos o las casillas.
Cómo encontrar elementos
Elegí usar atributos y valores para almacenar información sobre la animación deseada y cómo dividir el texto. Me gustó incluir estas opciones declarativas en el HTML. El atributo split-by
se usa desde JavaScript para encontrar elementos y crear cuadros para letras o palabras. El atributo letter-animation
o word-animation
se usa desde CSS para segmentar elementos secundarios y aplicar transformaciones y animaciones.
Este es un ejemplo de HTML que muestra los dos atributos:
<h1 split-by="letter" letter-animation="breath">animated letters</h1>
<h1 split-by="word" word-animation="trampoline">hover the words</h1>
Cómo encontrar elementos desde JavaScript
Usé la sintaxis del selector CSS para la presencia de atributos para recopilar la lista de elementos que desean que se divida su texto:
const splitTargets = document.querySelectorAll('[split-by]')
Cómo encontrar elementos a partir de CSS
También usé el selector de presencia de atributos en CSS para darles a todas las animaciones de letras los mismos estilos básicos. Más adelante, usaremos el valor del atributo para agregar estilos más específicos y lograr un efecto.
letter-animation {
@media (--motionOK) {
/* animation styles */
}
}
Cómo dividir texto en su lugar
Para cada uno de los destinos de división que encontramos en JavaScript, dividiremos su texto según el valor del atributo y asignaremos cada cadena a un <span>
. Luego, podemos reemplazar el texto del elemento por las casillas que creamos:
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)
}
})
Conclusión de la organización
index.js
en completitud:
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)
})
}
El código JavaScript se podría leer de la siguiente manera en español:
- Importa algunas funciones de utilidad auxiliares.
- Verifica si el movimiento es adecuado para este usuario. De lo contrario, no hagas nada.
- Es para cada elemento que se desea dividir.
- Divídelos según cómo quieran dividirse.
- Reemplaza el texto por elementos.
Cómo dividir animaciones y transiciones
La manipulación del documento de división anterior acaba de desbloquear una multitud de animaciones y efectos potenciales con CSS o JavaScript. Al final de este artículo, encontrarás algunos vínculos que te ayudarán a inspirarte para dividir tu contenido.
Es hora de mostrar lo que puedes hacer con esto. Compartiré 4 animaciones y transiciones basadas en CSS. 🤓
Dividir letras
Como base para los efectos de letras divididas, encontré que el siguiente código CSS es útil. Coloco todas las transiciones y animaciones detrás de la consulta de medios de movimiento y, luego, le doy a cada letra secundaria nueva span
una propiedad de visualización y un estilo para qué hacer con los espacios en blanco:
[letter-animation] > span {
display: inline-block;
white-space: break-spaces;
}
El estilo de espacios en blanco es importante para que el motor de diseño no contraiga los tramos que solo son un espacio. Ahora, pasemos a las cosas divertidas con estado.
Ejemplo de letras divididas en la transición
En este ejemplo, se usan transiciones de CSS para el efecto de texto dividido. Con las transiciones, necesitamos estados para que el motor pueda animar entre ellos, y elegí tres estados: sin desplazamiento, desplazamiento en la oración y desplazamiento sobre una letra.
Cuando el usuario coloca el cursor sobre la oración, también conocida como el contenedor, reduzco la escala de todos los elementos secundarios como si el usuario los hubiera alejado más. Luego, cuando el usuario coloca el cursor sobre una letra, la traigo al frente.
@media (--motionOK) {
[letter-animation="hover"] {
&:hover > span {
transform: scale(.75);
}
& > span {
transition: transform .3s ease;
cursor: pointer;
&:hover {
transform: scale(1.25);
}
}
}
}
Ejemplo de letras divididas animadas
En este ejemplo, se usa una animación @keyframe
predefinida para animar cada letra de forma infinita y se aprovecha el índice de propiedad personalizada intercalada para crear un efecto de escalonamiento.
@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;
}
}
Dividir palabras
Flexbox funcionó como un tipo de contenedor para mí en estos ejemplos, ya que aprovechó muy bien la unidad ch
como una longitud de separación adecuada.
word-animation {
display: inline-flex;
flex-wrap: wrap;
gap: 1ch;
}
Ejemplo de palabras divididas en la transición
En este ejemplo de transición, vuelvo a usar el desplazamiento del mouse. Como el efecto inicialmente oculta el contenido hasta que se coloca el cursor sobre él, me aseguré de que la interacción y los estilos solo se aplicaran si el dispositivo tenía la capacidad de colocar el cursor sobre el contenido.
@media (hover) {
[word-animation="hover"] {
overflow: hidden;
overflow: clip;
& > span {
transition: transform .3s ease;
cursor: pointer;
&:not(:hover) {
transform: translateY(50%);
}
}
}
}
Ejemplo de palabras divididas animadas
En este ejemplo de animación, vuelvo a usar @keyframes
de CSS para crear una animación infinita escalonada en un párrafo de texto normal.
[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;
}
}
Conclusión
Ahora que sabes cómo lo hice, ¿cómo lo harías tú? 🙂
Diversifiquemos nuestros enfoques y aprendamos todas las formas de crear contenido en la Web. Crea un Codepen o aloja tu propia demostración, envíame un tuit con ella y la agregaré a la sección de remixes de la comunidad que se encuentra a continuación.
Fuente
Más demostraciones e inspiración
Remixes de la comunidad
- Componente web de
<text-hover>
de gnehcwu en CodeSandbox