Créer des animations de texte fractionné

Présentation de base de la création d'animations de lettres et de mots fractionnés.

Dans cet article, je souhaite vous expliquer comment résoudre les problèmes d'animations de texte fractionné et d'interactions pour le Web qui sont minimes, accessibles et compatibles avec tous les navigateurs. Essayez la démonstration.

Démonstration

Si vous préférez la vidéo, voici une version YouTube de ce post:

Présentation

Les animations de fractionnement de texte peuvent être incroyables. Nous n'aborderons à peine que le potentiel d'animation dans cet article, mais il fournit une base sur laquelle s'appuyer. L'objectif est d'animer progressivement. Le texte doit être lisible par défaut, avec l'animation superposée. Les effets d'animation du texte fractionné peuvent devenir extravagants et potentiellement perturbateurs. Nous ne manipulerons donc le code HTML ou n'appliquons des styles d'animation que si l'utilisateur accepte le mouvement.

Voici un aperçu général du workflow et des résultats:

  1. Préparez des variables conditionnelles de mouvement réduites pour CSS et JS.
  2. Préparez les utilitaires de texte fractionné en JavaScript.
  3. Orchestrez les conditions et les utilitaires lors du chargement de la page.
  4. Écrivez des transitions et des animations CSS pour les lettres et les mots (la partie "rad" !).

Voici un aperçu des résultats conditionnels que nous allons obtenir:

Capture d'écran des outils de développement Chrome avec le panneau "Elements" ouvert, la réduction du mouvement est définie sur "réduction" et "h1" s'affiche sans fractionnement
L'utilisateur préfère un mouvement réduit: le texte est lisible / non fractionné

Si un utilisateur préfère un mouvement réduit, nous laissons le document HTML tel quel et ne réalisons aucune animation. Si le mouvement est accepté, nous allons le découper en morceaux. Voici un aperçu du code HTML une fois que JavaScript a divisé le texte par lettre.

Capture d'écran des outils de développement Chrome avec le panneau "Elements" ouvert, la réduction du mouvement est définie sur "réduction" et "h1" s'affiche sans fractionnement
L'utilisateur accepte les mouvements ; le texte est divisé en plusieurs éléments <span>

Préparer des conditions de mouvement

La requête média @media (prefers-reduced-motion: reduce), pratiquement disponible, sera utilisée à partir de CSS et de JavaScript dans ce projet. Cette requête média est notre condition principale pour décider de diviser le texte ou non. La requête média CSS permet de suspendre les transitions et les animations, tandis que la requête média JavaScript permet de suspendre la manipulation HTML.

Préparer l'instruction conditionnelle CSS

J'ai utilisé PostCSS pour activer la syntaxe des requêtes média de niveau 5, dans laquelle je peux stocker une requête média de niveau 5 dans une variable:

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

Préparer l'instruction conditionnelle JS

En JavaScript, le navigateur offre un moyen de vérifier les requêtes média. J'ai utilisé la déstructuration pour extraire et renommer le résultat booléen de la vérification des requêtes média:

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

Je peux ensuite tester motionOK et ne modifier le document que si l'utilisateur n'a pas demandé à réduire le mouvement.

if (motionOK) {
  // document split manipulations
}

Je peux vérifier la même valeur en utilisant PostCSS pour activer la syntaxe @nest à partir de l'imbrication brouillon 1. Cela me permet de stocker toute la logique de l'animation et ses exigences de style pour le parent et les enfants, en un seul endroit:

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

Avec la propriété personnalisée PostCSS et une valeur booléenne JavaScript, nous pouvons mettre à niveau l'effet de manière conditionnelle. Cela nous amène à la section suivante, dans laquelle je décompose le JavaScript pour transformer les chaînes en éléments.

Division du texte

Vous ne pouvez pas animer individuellement les lettres, les mots, les lignes, etc. avec CSS ou JS. Pour obtenir cet effet, nous avons besoin de cadres. Si nous voulons animer chaque lettre, alors chaque lettre doit être un élément. Si nous voulons animer chaque mot, alors chaque mot doit être un élément.

  1. Créer des fonctions utilitaires JavaScript permettant de diviser des chaînes en éléments
  2. Orchestrer l'utilisation de ces utilitaires

Fonction utilitaire de division de lettres

Vous pouvez commencer par utiliser une fonction qui prend une chaîne et renvoie chaque lettre d'un tableau.

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

La syntaxe de spread d'ES6 a vraiment contribué à rendre cette tâche rapide.

Fonction utilitaire de division des mots

Semblable à la division des lettres, cette fonction prend une chaîne et renvoie chaque mot d'un tableau.

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

La méthode split() sur les chaînes JavaScript nous permet de spécifier les caractères à utiliser pour le segment. J'ai transmis un espace vide, indiquant une séparation entre les mots.

Créer une fonction utilitaire de boîtes

L'effet nécessite des cases pour chaque lettre, et nous voyons dans ces fonctions que map() est appelé avec une fonction span(). Voici la fonction span().

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

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

  return node
}

Il est important de noter qu'une propriété personnalisée appelée --index est définie avec la position du tableau. Disposer de zones de texte pour les animations de lettres est pratique, mais disposer d'un index à utiliser en CSS est un ajout en apparence mineur, ayant un impact important. Le plus notable de cet impact est stupéfiant. Nous pourrons utiliser --index pour décaler les animations pour obtenir un résultat décalé.

Conclusion sur les utilitaires

Module splitting.js terminé:

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)

Vous allez ensuite importer et utiliser ces fonctions byLetter() et byWord().

Orchestration partagée

Maintenant que les utilitaires de fractionnement sont prêts à être utilisés, assembler le tout donne les résultats suivants:

  1. Trouver les éléments à diviser
  2. en les divisant et en les remplaçant par du code HTML ;

Ensuite, CSS prend le relais et anime les éléments / cases.

Recherche d'éléments

J'ai choisi d'utiliser des attributs et des valeurs pour stocker des informations sur l'animation souhaitée et sur la façon de diviser le texte. J'aimais intégrer ces options déclaratives dans le code HTML. L'attribut split-by est utilisé à partir de JavaScript pour rechercher des éléments et créer des zones pour des lettres ou des mots. L'attribut letter-animation ou word-animation est utilisé dans CSS pour cibler les éléments enfants des éléments, et appliquer des transformations et des animations.

Voici un exemple de code HTML illustrant les deux attributs:

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

Recherche d'éléments à partir de JavaScript

J'ai utilisé la syntaxe du sélecteur CSS pour la présence d'attributs afin de rassembler la liste des éléments dont le texte doit être fractionné:

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

Rechercher des éléments à partir du code CSS

J'ai également utilisé le sélecteur de présence d'attribut en CSS pour attribuer à toutes les animations de lettres les mêmes styles de base. Plus tard, nous utiliserons la valeur de l'attribut pour ajouter des styles plus spécifiques afin d'obtenir un effet.

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

Division du texte en cours

Pour chacune des cibles de fractionnement que nous trouvons dans JavaScript, nous allons diviser le texte en fonction de la valeur de l'attribut et mapper chaque chaîne à une <span>. Nous pouvons ensuite remplacer le texte de l'élément par les zones que nous avons créées:

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

Conclusion de l'orchestration

index.js terminé:

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

Le JavaScript peut être lu dans les langues suivantes:

  1. Importez des fonctions utilitaires d'assistance.
  2. Vérifiez si les mouvements peuvent être effectués par l'utilisateur. Si ce n'est pas le cas, ne faites rien.
  3. Pour chaque élément à scinder.
    1. Répartissez-les en fonction de la manière dont ils le souhaitent.
    2. Remplacez du texte par des éléments.

Diviser des animations et des transitions

La manipulation de documents de division ci-dessus vient de débloquer une multitude d'animations et d'effets potentiels avec CSS ou JavaScript. Vous trouverez quelques liens au bas de cet article pour vous inspirer de votre potentiel de division.

Voyons ce que vous pouvez en faire ! Je vais partager quatre transitions et animations basées sur CSS. 🤓

Diviser les lettres

J'ai trouvé que le code CSS suivant était utile pour créer les effets de lettres scindées. J'ai placé toutes les transitions et animations derrière la requête multimédia de mouvement, puis j'attribue à chaque nouvelle lettre enfant span une propriété d'affichage et un style pour ce qu'il faut faire avec les espaces blancs:

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

Le style des espaces blancs est important pour que les éléments Span qui ne sont qu'un espace ne soient pas réduits par le moteur de mise en page. Passons maintenant aux choses amusantes avec état.

Exemple de lettres fractionnées de transition

Cet exemple utilise des transitions CSS pour l'effet de fractionnement du texte. Pour les transitions, nous avons besoin d'états pour que le moteur s'anime. J'ai choisi trois états: pas de survol, pointage dans la phrase et survol sur une lettre.

Lorsque l'utilisateur pointe sur la phrase (c'est-à-dire le conteneur), j'effectue un scaling à la baisse de tous les enfants comme si l'utilisateur les avait repoussés un peu plus loin. Ensuite, lorsque l'utilisateur passe la souris sur une lettre, je l'avance.

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

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

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

Exemple d'animation de lettres divisées

Cet exemple utilise une animation @keyframe prédéfinie pour animer infiniment chaque lettre et exploite l'index de propriété personnalisée intégré pour créer un effet de décalage.

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

Diviser les mots

Dans ces exemples, Flexbox a fonctionné comme un type de conteneur, exploitant bien l'unité ch en tant que longueur d'écart saine.

word-animation {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1ch;
}
Outils de développement Flexbox montrant l'écart entre les mots

Exemple de division des transitions

Dans cet exemple de transition, j'utilise de nouveau la souris. Comme l'effet masque initialement le contenu jusqu'au survol, je me suis assuré que l'interaction et les styles n'étaient appliqués que si l'appareil pouvait pointer dessus.

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

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

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

Exemple de division d'animation

Dans cet exemple d'animation, j'utilise à nouveau CSS @keyframes pour créer une animation infinie décalée sur un paragraphe de texte standard.

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

Conclusion

Maintenant que tu sais comment j'ai fait, comment tu en ferais ?! 🙂

Diversissons nos approches et apprenons toutes les façons de créer sur le Web. Créez un Codepen ou animez votre propre démo. Envoyez-moi un tweet à mon adresse e-mail pour que je l'ajoute à la section "Remix de la communauté" ci-dessous.

Source

Plus de démonstrations et d'inspiration

Remix de la communauté