Créer des animations de texte fractionné

Présentation générale de la création d'animations de lettres et de mots fractionnées

Dans ce post, je veux partager la réflexion sur les façons de résoudre les animations de texte fractionné et des interactions 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 cet article:

Présentation

Les animations de texte fractionné peuvent être incroyables. Nous allons à peine effleurer la surface de potentiel d'animation dans cet article, mais il fournit une base pour construire de données. L'objectif est l'animation progressive. Le texte doit être lisible par par défaut, avec l'animation construite sur le dessus. Les effets de mouvement de fractionnement du texte peuvent extravagants et potentiellement gênants, nous ne manipulerons que du code HTML, ou appliquer des styles de mouvement si l'utilisateur est d'accord avec le mouvement.

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

  1. Préparer la réduction des mouvements conditionnels pour CSS et JavaScript.
  2. Préparer les utilitaires de texte fractionné dans JavaScript.
  3. Orchestrer les instructions conditionnelles et les utilitaires sur la page de votre application.
  4. Écrire des animations et des transitions CSS des lettres et des mots (la partie spéciale !).

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

Capture d'écran des outils de développement Chrome avec le panneau "Elements" ouvert et l'option "Reduce" (réduction des mouvements) définie sur "reduce" et "h1" s'affiche non fractionné
L'utilisateur préfère les mouvements réduits: le texte est lisible / non fractionné.

Si un utilisateur préfère réduire les mouvements, nous laissons le document HTML tel quel et nous ne de l'animation. Si le mouvement est acceptable, nous le découpons en plusieurs parties. Voici un Aperçu du code HTML après que JavaScript a divisé le texte par lettre

Capture d'écran des outils de développement Chrome avec le panneau "Elements" ouvert et l'option "Reduce" (réduction des mouvements) définie sur "reduce" et "h1" s'affiche non fractionné
L'utilisateur est d'accord avec les mouvements. texte divisé en plusieurs <span> éléments

Préparer des instructions conditionnelles de mouvement

La requête média @media (prefers-reduced-motion: reduce), disponible, qui est pratique, sera utilisée à partir du CSS et JavaScript dans ce projet. Cette requête média est notre condition principale pour décider de scinder le texte ou non. La requête média CSS sera utilisée pour retenir les transitions et les animations, tandis que la requête média JavaScript sera utilisée pour ne pas manipuler HTML.

Préparer l'instruction CSS conditionnelle

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

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

Préparer l'instruction conditionnelle JS

En JavaScript, le navigateur permet de vérifier les requêtes média. déstructuration pour extraire et renommer le résultat booléen du contrôle de requête média:

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

Je peux ensuite tester motionOK et modifier le document uniquement si l'utilisateur n'a pas de réduire les mouvements.

if (motionOK) {
  // document split manipulations
}

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

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

Avec la propriété personnalisée PostCSS et une valeur booléenne JavaScript, nous pouvons pour améliorer l'effet de manière conditionnelle. Cela nous amène à la section suivante où je décomposer le code JavaScript pour transformer des chaînes en éléments.

Scinder du texte

Les lettres, les mots, les lignes, etc. ne peuvent pas être animés individuellement avec CSS ou JS. Pour obtenir l'effet, il nous faut des cases. Si nous voulons animer chaque lettre, chaque lettre doit être un élément. Si nous voulons animer chaque mot, le mot doit être un élément.

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

Fonction utilitaire de division de lettres

Un bon point de départ consiste à utiliser une fonction qui prend une chaîne et renvoie chaque dans un tableau.

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

La répartir la syntaxe d'ES6 ont 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 dans un tableau.

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

La split() sur les chaînes JavaScript nous permet de spécifier les caractères à segmenter. J'ai inséré un espace vide, indiquant une division entre les mots.

Réaliser une fonction utilitaire des 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 essentiel de noter qu'une propriété personnalisée appelée --index est définie avec la position du tableau. Avoir les cases pour les animations de lettres est génial, mais Avoir un index à utiliser en CSS est un ajout apparemment petit, avec un impact important. Le plus notable à cause de cet impact important est stupéfiant. Nous pourrons utiliser --index pour décaler les animations d'un événement décalé un style.

Conclusion concernant 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)

L'étape suivante consiste à importer et à utiliser ces fonctions byLetter() et byWord().

Orchestration partagée

Une fois les utilitaires de division prêts à l'emploi, assembler le tout donne:

  1. Trouver les éléments à diviser
  2. Diviser ces éléments et remplacer le texte par du code HTML

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

Éléments du résultat

J'ai choisi d'utiliser des attributs et des valeurs pour stocker des informations et comment diviser le texte. J'ai aimé proposer ces options déclaratives dans le code HTML. L'attribut split-by est utilisé à partir de JavaScript pour rechercher et créer des zones pour les lettres ou les mots. L'attribut letter-animation ou word-animation est utilisé dans le code CSS pour cibler l'élément. et appliquer des transformations et des animations.

Voici un exemple de code HTML qui illustre ces deux attributs:

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

Rechercher des é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 pour lesquels le texte doit être divisé:

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

Rechercher des éléments à partir du CSS

J'ai également utilisé le sélecteur de présence d'attribut en CSS pour afficher toutes les animations de lettres les mêmes styles de base. Plus tard, nous utiliserons la valeur de l'attribut pour ajouter différents styles pour obtenir un effet.

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

Division du texte

Pour chaque cible de fractionnement trouvée dans JavaScript, nous diviserons le texte en fonction de la valeur de l'attribut et mappez chaque chaîne à un <span>. Nous pouvons puis remplacez le texte de l'élément par les cases 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 sur l'orchestration

index.js terminés:

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 l'anglais suivant:

  1. Importez des fonctions utilitaires d'assistance.
  2. Vérifiez si les mouvements sont autorisés pour cet utilisateur. Si ce n'est pas le cas, ne faites rien.
  3. Pour chaque élément à diviser.
    1. Divisez-les en fonction de la manière dont elles doivent l'être.
    2. Remplacez le texte par des éléments.

Diviser des animations et des transitions

La manipulation du document de division ci-dessus vient de débloquer une multitude les animations et les effets potentiels avec CSS ou JavaScript. Il y a quelques liens au bas de cet article pour vous aider à trouver une idée de votre potentiel de division.

Il est temps de montrer ce que vous pouvez faire ! Je partagerai 4 animations CSS et les transitions. 🤓

Diviser les lettres

Comme base pour les effets de lettres fractionnées, j'ai constaté que le CSS suivant était utiles. J’ai placé toutes les transitions et animations derrière la requête média de mouvement et puis attribuer à chaque nouvelle lettre enfant span une propriété d'affichage et un style pour à voir avec les espaces:

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

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

Exemple de lettres de transition fractionnées

Cet exemple utilise des transitions CSS vers l'effet de fractionnement de texte. Avec les transitions, nous des états nécessaires pour que le moteur s'anime. J'ai choisi trois états: non survoler, survoler dans une phrase, survoler une lettre.

Lorsque l'utilisateur pointe sur la phrase, ou conteneur, je réduis l'ensemble les enfants comme si l'utilisateur les repoussait. Ensuite, lorsque l'utilisateur pointe de la lettre d'information, je l'amène.

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

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

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

Animer des lettres fractionnées

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

@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 en mots

Flexbox a fonctionné comme un type de conteneur pour moi dans ces exemples. Utiliser l'unité ch comme une longueur d'écart correcte.

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

Exemple de mots séparés par une transition

Dans cet exemple de transition, j'utilise à nouveau le survol. Étant donné que l'effet masque initialement jusqu'au passage de la souris, je me suis assuré que l'interaction et les styles n'étaient appliqués si l'appareil pouvait survoler l'écran.

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

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

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

Animer des mots fractionnés

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

[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 faire ?! 🙂

Diversifiez nos approches et découvrons toutes les manières de créer des applications sur le Web. Créez un Codepen ou hébergez votre propre démo, envoyez-moi un tweet pour que je l'ajoute au section "Remix de la communauté" ci-dessous.

Source

Plus de démos et d'inspiration

Remix de la communauté