Présentation de base sur la création d'animations de lettres et de mots fractionnés.
Dans cet article, je souhaite partager des réflexions sur les solutions permettant de créer des animations et des interactions de texte fractionné pour le Web qui sont minimales, accessibles et compatibles avec tous les navigateurs. Essayez la démo.
Si vous préférez regarder une vidéo, voici une version YouTube de cet article:
Présentation
Les animations de texte fractionné peuvent être incroyables. Dans cet article, nous ne ferons qu'effleurer le potentiel de l'animation, mais il constitue une base sur laquelle vous pourrez vous appuyer. L'objectif est d'animer progressivement. Le texte doit être lisible par défaut, avec l'animation intégrée par-dessus. Les effets de mouvement du texte fractionné peuvent être extravagants et potentiellement gênants. Nous ne manipulerons donc que le code HTML ou appliquerons des styles de mouvement si l'utilisateur accepte le mouvement.
Voici un aperçu général du workflow et des résultats:
- Préparez des variables conditionnelles de mouvement réduit pour CSS et JS.
- Préparez les utilitaires de fractionnement de texte en JavaScript.
- Orchestrez les conditions et les utilitaires au chargement de la page.
- Écrivez des transitions et des animations CSS pour les lettres et les mots (la partie la plus cool !).
Voici un aperçu des résultats conditionnels que nous souhaitons obtenir:
Si un utilisateur préfère réduire le mouvement, nous laissons le document HTML tel quel et n'effectuons aucune animation. Si le mouvement est correct, nous pouvons le découper en morceaux. Voici un aperçu du code HTML après que JavaScript a divisé le texte par lettre.
Préparer des conditions de mouvement
La requête multimédia @media
(prefers-reduced-motion: reduce)
, qui est disponible, sera utilisée à partir de CSS et de JavaScript dans ce projet. Cette requête multimédia est notre condition principale pour décider de diviser le texte ou non. La requête média CSS permet de bloquer les transitions et les animations, tandis que la requête média JavaScript permet de bloquer la manipulation HTML.
Préparer l'instruction conditionnelle CSS
J'ai utilisé PostCSS pour activer la syntaxe des requêtes multimédias de niveau 5, où je peux stocker une requête multimédia booléenne dans une variable:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
Préparer la condition JS
En JavaScript, le navigateur permet de vérifier les requêtes multimédias. J'ai utilisé la déstructuration pour extraire et renommer le résultat booléen de la vérification des requêtes multimédias:
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 à l'aide de PostCSS pour activer la syntaxe @nest
de la version préliminaire 1 de l'imbrication. Cela me permet de stocker toute la logique de l'animation et ses exigences de style pour le parent et les enfants au même endroit:
letter-animation {
@media (--motionOK) {
/* animation styles */
}
}
Avec la propriété personnalisée PostCSS et une valeur booléenne JavaScript, nous sommes prêts à mettre à niveau l'effet de manière conditionnelle. Nous passons maintenant à la section suivante, où je détaille le code JavaScript permettant de transformer des chaînes en éléments.
Scinder le texte
Vous ne pouvez pas animer individuellement les lettres, les mots, les lignes, etc. d'un texte avec CSS ou JS. Pour obtenir cet effet, nous avons besoin de cases. Si nous voulons animer chaque lettre, chaque lettre doit être un élément. Si nous voulons animer chaque mot, chaque mot doit être un élément.
- Créer des fonctions utilitaires JavaScript pour diviser des chaînes en éléments
- Orchestration de l'utilisation de ces utilitaires
Fonction utilitaire de fractionnement des lettres
Un bon point de départ est une fonction qui prend une chaîne et renvoie chaque lettre dans un tableau.
export const byLetter = text =>
[...text].map(span)
La syntaxe de propagation d'ES6 a vraiment contribué à accélérer cette tâche.
Fonction utilitaire de division des mots
Comme pour 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 méthode split()
sur les chaînes JavaScript nous permet de spécifier les caractères à découper.
J'ai transmis un espace vide, ce qui indique une séparation entre les mots.
Créer une fonction utilitaire de boîtes
L'effet nécessite des cases pour chaque lettre. Dans ces fonctions, nous voyons 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. Les cases pour les animations de lettres sont très utiles, mais disposer d'un indice à utiliser dans le CSS est un ajout apparemment mineur qui a un impact important.
L'impact de cette augmentation est particulièrement notable.
Nous pourrons utiliser --index
pour décaler les animations afin d'obtenir un effet étalé.
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)
Importez et utilisez ensuite ces fonctions byLetter()
et byWord()
.
Orchestration de la répartition
Une fois les utilitaires de fractionnement prêts à l'emploi, voici ce que vous devez faire:
- Identifier les éléments à diviser
- Diviser les éléments et remplacer le texte par du code HTML
Ensuite, le CSS prend le relais et anime les éléments / boîtes.
Rechercher des éléments
J'ai choisi d'utiliser des attributs et des valeurs pour stocker des informations sur l'animation souhaitée et la façon de diviser le texte. J'ai aimé mettre 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 cases pour des lettres ou des mots. L'attribut letter-animation
ou word-animation
est utilisé à partir du CSS pour cibler les enfants d'un élément 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>
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 éléments dont 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'attributs en CSS pour attribuer les mêmes styles de base à toutes les animations de lettres. 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 */
}
}
Scinder le texte en place
Pour chacune des cibles de fractionnement que nous trouvons dans JavaScript, nous allons diviser leur texte en fonction de la valeur de l'attribut et mapper chaque chaîne sur un <span>
. Nous pouvons ensuite remplacer 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 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 code JavaScript peut être lu en anglais comme suit:
- Importez des fonctions utilitaires d'assistance.
- Vérifiez si le mouvement est autorisé pour cet utilisateur. Si ce n'est pas le cas, ne faites rien.
- Pour chaque élément à diviser.
- Les diviser en fonction de la façon dont ils veulent être divisés.
- Remplacez le texte par des éléments.
Diviser les animations et les transitions
La manipulation de document de fractionnement ci-dessus vient de débloquer une multitude d'animations et d'effets potentiels avec CSS ou JavaScript. Vous trouverez quelques liens en bas de cet article pour vous aider à trouver des idées de scission.
Il est temps de montrer ce que vous pouvez faire avec ! Je vais partager quatre animations et transitions CSS. 🤓
Diviser les lettres
En tant que base pour les effets de lettres fractionnées, le CSS suivant s'est avéré utile. J'ai placé toutes les transitions et animations derrière la requête de contenu multimédia de mouvement, puis j'ai attribué à chaque nouvelle lettre enfant span
une propriété d'affichage et un style pour indiquer 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 plages qui ne sont qu'un espace ne soient pas réduites par le moteur de mise en page. Passons maintenant aux choses amusantes avec l'état.
Exemple de lettres fractionnées de transition
Cet exemple utilise des transitions CSS pour l'effet de texte fractionné. Avec les transitions, nous avons besoin d'états pour que le moteur puisse animer. J'ai choisi trois états: pas de survol, survol dans la phrase, survol d'une lettre.
Lorsque l'utilisateur pointe sur la phrase, c'est-à-dire le conteneur, je réduis la taille de tous les enfants comme si l'utilisateur les avait éloignés. Ensuite, lorsque l'utilisateur pointe sur une lettre, je la mets en avant.
@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 fractionnées
Cet exemple utilise une animation @keyframe
prédéfinie pour animer chaque lettre à l'infini et exploite l'index de propriété personnalisée intégrée 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 en mots
Dans ces exemples, Flexbox a fonctionné comme type de conteneur, en exploitant de manière appropriée l'unité ch
comme longueur d'espace appropriée.
word-animation {
display: inline-flex;
flex-wrap: wrap;
gap: 1ch;
}
Exemple de mots de transition fractionnés
Dans cet exemple de transition, j'utilise à nouveau le survol. Comme l'effet masque initialement le contenu jusqu'à ce que l'utilisateur le survole, je me suis assuré que l'interaction et les styles n'étaient appliqués que si l'appareil était capable de le faire.
@media (hover) {
[word-animation="hover"] {
overflow: hidden;
overflow: clip;
& > span {
transition: transform .3s ease;
cursor: pointer;
&:not(:hover) {
transform: translateY(50%);
}
}
}
}
Exemple d'animation de mots divisés
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 vous savez comment j'ai fait, comment pourriez-vous faire ? 🙂
Diversifions nos approches et découvrons toutes les façons de créer sur le Web. Créez un Codepen ou hébergez votre propre démonstration, tweetez-moi avec, et je l'ajouterai à la section "Remix de la communauté" ci-dessous.
Source
Plus de démonstrations et d'inspiration
Remix de la communauté
- Composant Web
<text-hover>
par gnehcwu sur CodeSandbox