Descripción general de cómo crear animaciones con letras y palabras divididas
En esta publicación, quiero compartir mis ideas sobre cómo resolver animaciones y interacciones de texto divididas para la Web que sean minimalistas, accesibles y funcionen en todos los navegadores. Prueba la demostración.
Si prefieres ver un video, aquí tienes una versión de esta publicación en YouTube:
Descripción general
Las animaciones de texto dividido pueden ser increíbles. En esta publicación, apenas analizaremos la superficie del potencial de animación, pero proporciona una base sobre la cual desarrollar. El objetivo es animar de forma progresiva. El texto debe ser legible de forma predeterminada, con la animación integrada en la parte superior. Los efectos de movimiento de texto dividido pueden ser extravagantes y potencialmente disruptivos, por lo que solo manipularemos el HTML o aplicaremos estilos de movimiento si el usuario está de acuerdo con el movimiento.
Esta es una descripción general del flujo de trabajo y los resultados:
- Prepara las variables condicionales de movimiento reducido para CSS y JS.
- Prepara las utilidades de texto dividido en JavaScript.
- Organiza las condiciones y las utilidades cuando se carga la página.
- Escribe transiciones y animaciones de CSS para letras y palabras (la parte genial).
Esta es una vista previa de los resultados condicionales que buscamos:
Si un usuario prefiere reducir el movimiento, dejamos el documento HTML intacto y no realizamos ninguna animación. Si el movimiento está bien, podemos continuar y cortarlo en pedazos. A continuación, se muestra una vista previa del código HTML después de que JavaScript haya dividido el texto por letra.
Prepara condiciones de movimiento
La consulta de medios @media
(prefers-reduced-motion: reduce)
disponible de forma conveniente se usará desde CSS y JavaScript en este proyecto. Esta consulta de medios es nuestra condición principal para decidir si dividir el texto o no. La consulta de medios de CSS se usará para retener las transiciones y las animaciones, mientras que la consulta de medios de JavaScript se usará para retener la manipulación de HTML.
Prepara el condicional de CSS
Usé PostCSS para habilitar la sintaxis del nivel 5 de las consultas de medios, en el que puedo almacenar un valor booleano de consulta de medios en una variable:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
Prepara el condicional de JS
En JavaScript, el navegador proporciona una forma de verificar las consultas multimedia. Usé la desestructuración para extraer y cambiar el nombre del resultado booleano de la verificación de la consulta multimedia:
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
del borrador de anidación 1. Esto me permite almacenar toda la lógica sobre la animación y sus requisitos de estilo para el elemento superior y los secundarios en un solo lugar:
letter-animation {
@media (--motionOK) {
/* animation styles */
}
}
Con la propiedad personalizada de PostCSS y un booleano de JavaScript, estamos listos para actualizar el efecto de forma condicional. Esto nos lleva a la siguiente sección, en la que desgloso JavaScript para transformar cadenas en elementos.
Cómo dividir texto
Las letras, palabras, líneas, etc., de texto no se pueden animar de forma individual con CSS o JS. Para lograr el efecto, necesitamos cuadros. Si queremos animar cada letra, cada letra debe ser un elemento. Si queremos animar cada palabra, cada una de ellas debe ser un elemento.
- Crea funciones de utilidad de JavaScript para dividir cadenas en elementos
- Orquestar el uso de estas utilidades
Función de utilidad de división de letras
Un lugar divertido para comenzar es con una función que toma una cadena y muestra cada letra de un array.
export const byLetter = text =>
[...text].map(span)
La sintaxis desplegada de ES6 realmente ayudó a que esa tarea fuera una tarea rápida.
Función de utilidad para dividir palabras
Al igual que dividir letras, esta función toma una cadena y muestra cada palabra en un array.
export const byWord = text =>
text.split(' ').map(span)
El método split()
en las cadenas de JavaScript nos permite especificar en qué caracteres cortar.
Pasé un espacio vacío, lo que indica una división entre palabras.
Cómo hacer que las cajas funcionen como utilidad
El efecto requiere cuadros 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 los cuadros 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 que es desordenado.
Podremos usar --index
como una forma de compensar animaciones para lograr un aspecto escalonado.
Conclusión de las utilidades
El módulo splitting.js
completo:
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, importaremos y usaremos estas funciones byLetter()
y byWord()
.
Organización dividida
Con las utilidades de división listas para usar, poner todo en orden significa lo siguiente:
- Encuentra qué elementos dividir
- Dividiéndolos y reemplazando el texto con HTML
Después de eso, el CSS se hará cargo y animará los elementos o cuadros.
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ó colocar
estas opciones declarativas en HTML. El atributo split-by
se usa desde JavaScript para buscar elementos y crear cuadros para letras o palabras. El atributo letter-animation
o word-animation
se usa desde CSS para orientarse a elementos secundarios y aplicar transformaciones y animaciones.
Este es un ejemplo de código 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 desde CSS
También usé el selector de presencia de atributos en CSS para dar a todas las animaciones de letras los mismos estilos base. Más adelante, usaremos el valor del atributo para agregar diseños más específicos y lograr un efecto.
letter-animation {
@media (--motionOK) {
/* animation styles */
}
}
Cómo dividir el texto en su lugar
Para cada uno de los objetivos de división que encontremos en JavaScript, dividiremos el texto según el valor del atributo y asignaremos cada cadena a un <span>
. Luego, podemos reemplazar el texto del elemento por los cuadros que hicimos:
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
completado:
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 en el siguiente inglés:
- Importa algunas funciones de utilidad auxiliares.
- Verifica si el movimiento es adecuado para este usuario. De lo contrario, no hagas nada.
- Para cada elemento que se quiere dividir.
- Dividirlos según cómo quieran dividirlos
- Reemplaza el texto por elementos.
Cómo dividir animaciones y transiciones
La manipulación de documentos de división anterior acaba de desbloquear una gran cantidad de animaciones y efectos potenciales con CSS o JavaScript. Hay algunos vínculos en la parte inferior de este artículo que te ayudarán a inspirar tu potencial de división.
Es hora de mostrar lo que puedes hacer con esto. Compartiré 4 animaciones y transiciones impulsadas por CSS. 🤓
Dividir letras
Como base para los efectos de letras divididas, el siguiente CSS me resultó útil. Puse todas las transiciones y animaciones detrás de la consulta de medios de movimiento y, luego, le di a cada letra secundaria nueva span
una propiedad de visualización y un estilo para lo que se debe hacer con los espacios en blanco:
[letter-animation] > span {
display: inline-block;
white-space: break-spaces;
}
El estilo de los espacios en blanco es importante para que el motor de diseño no contraiga los tramos que son solo un espacio. Ahora, vamos a lo divertido con el estado.
Ejemplo de letras divididas de 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 anime entre ellos, y elegí tres estados: sin desplazamiento del mouse, desplazamiento del mouse en una oración y desplazamiento del mouse sobre una letra.
Cuando el usuario coloca el cursor sobre la oración, también conocida como contenedor, reduzco todos los elementos secundarios como si el usuario los hubiera alejado. Luego, cuando el usuario coloca el cursor sobre una letra, la muestro.
@media (--motionOK) {
[letter-animation="hover"] {
&:hover > span {
transform: scale(.75);
}
& > span {
transition: transform .3s ease;
cursor: pointer;
&:hover {
transform: scale(1.25);
}
}
}
}
Ejemplo de animación de letras divididas
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 espaciado.
@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 tipo de contenedor para mí en estos ejemplos, lo que aprovechó bien la unidad ch
como una longitud de espacio saludable.
word-animation {
display: inline-flex;
flex-wrap: wrap;
gap: 1ch;
}
Ejemplo de palabras divididas de transición
En este ejemplo de transición, vuelvo a usar el cursor sobre un elemento. Como el efecto inicialmente oculta el contenido hasta que se coloca el cursor sobre un elemento, me aseguré de que la interacción y los diseños solo se aplicaran si el dispositivo tuviera la capacidad de colocar el cursor sobre ellos.
@media (hover) {
[word-animation="hover"] {
overflow: hidden;
overflow: clip;
& > span {
transition: transform .3s ease;
cursor: pointer;
&:not(:hover) {
transform: translateY(50%);
}
}
}
}
Ejemplo de animación de palabras divididas
En este ejemplo de animación, vuelvo a usar CSS @keyframes
para crear una animación infinita intercalada 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? 🙂
Diversifiquemos nuestros enfoques y aprendamos todas las formas de compilar en la Web. Crea una cuenta de Codepen o aloja tu propia demo, envíame un tweet con ella y la agregaré a la sección de remixes de la comunidad a continuación.
Fuente
Más inspiración y demostraciones
Remixes de la comunidad
- Componente web
<text-hover>
de gnehcwu en CodeSandbox