• Serious Devs
  • Home
  • Blog
  • Contact

📅 25/05/2023

Frontend HTML CSS

Animation de texte Ă  l'infini

Ne perdons pas de temps, voici l'effet que je cherche Ă  reproduire.

Your browser does not support the video tag.

J'ai trouvé des exemples similaires sur la toile, par exemple le premier sur cette page. Mais le cÎté infini du mouvement n'est pas trÚs convaincant. On y voit un blanc avant de reprendre.

Je me suis donc mis en tĂȘte de reproduire cet effet par moi-mĂȘme.

Les resources

Si vous ĂȘtes impatient, vous trouverez les sources du rĂ©sultat final sur ce repository.

Structuration du DOM

Dans cet effet, nous avons un titre principal et plusieurs sous-titres.

Pour ne faire apparaitre qu'un seul sous-titre Ă  la fois, je veux pouvoir les placer comme bon me semble dans un <div>, y compris en dehors de l'espace visible de ce <div>. Et bien sĂ»r, si le sous-titre dĂ©borde, il doit ĂȘtre cachĂ©.

Je vais donc mettre en place la structure suivante :


<div class="title-box"> <!-- J'entoure avec cet autre div uniquement pour pouvoir le placer dans une page -->
    <h1>Titre principal</h1>
    <div> <!-- Ce div va définir l'espace visible, je l'appellerai parfois <div> encadrant -->
        <div>Sous-titre 1</div>
        <div>Sous-titre 2</div>
        <div>Sous-titre 3</div>
    </div>
</div>

En l'état, voici ce que ça donne et on est d'accord, c'est moche pour le moment :

Titre principal
Sous-titre 1
Sous-titre 2
Sous-titre 3

Un peu de style

Tout d'abord, on va resserrer un peu tout ça en enlevant les marges sur le titre :

h1 {
    margin: 0;
}
Titre principal
Sous-titre 1
Sous-titre 2
Sous-titre 3

L'étape suivante est importante. Elle va me donner le pouvoir de placer mes sous-tires comme bon me semble dans le <div> qui les entoure. Et en fait, c'est assez simple, le <div> en question va prendre une position: relative; et chaque sous-titre va prendre une position position: absolute;. Les sous-titres auront une position qui est absolue relativement au parent.

Le seul hic est qu'en spécifiant la position: relative;, le <div> ne prend plus tout seul toute la place dont il a besoin et donc, on va l'aider un peu en lui spécifiant une hauteur.

.title-box > div {
    position: relative;
    height: 1.5em;
}

.title-box > div > div {
    position: absolute;
}
Titre principal
Sous-titre 1
Sous-titre 2
Sous-titre 3

Et c'est encore plus moche qu'avant car tous les sous-titres sont les uns sur les autres. Mais c'est exactement le pouvoir que je voulais acquérir. C'est-à-dire que j'ai le pouvoir de rendre tout ça encore plus moche avec la propriété top par exemple.

.title-box > div > div {
    position: absolute;
    top: -1.5em;
}
Titre principal
Sous-titre 1
Sous-titre 2
Sous-titre 3

Et voilĂ , les sous-titres sont non seulement les uns sur les autres et en plus, ils chevauchent le titre principal. La bonne nouvelle, c'est qu'ils ne sont plus dans la zone visible de notre <div> encadrant. On peut donc les cacher avec un petit overflow: hidden;.

.title-box > div {
    position: relative;
    height: 1.5em;
    overflow: hidden;
}
Titre principal
Sous-titre 1
Sous-titre 2
Sous-titre 3

Nous voilĂ  avec des sous-titres bien prĂ©sents dans le DOM, mais cachĂ© et prĂȘt Ă  se faire animer.

Une petite précision, vous aurez remarqué que j'utilise des em comme unité pour définir la hauteur du <div> et pour la position des sous-titres. Cette unité permet de s'adapter à la taille de la font utilisée pour les sous-titres. Par contre, pour que celà fonctionne, la taille de la font devra préciser sur le <div> encadrant.

Animations

Le but du jeu, pour que le code ne devienne pas trop compliqué, est de définir une seule animation qui fonctionnera pour les trois sous-titres. Et grùce à un délai au démarrage, on obtiendra une fluidité dans le mouvement. Voici à quoi peut ressembler l'animation CSS :

@keyframes subtitle-rolling {
    0% {
        top: -1.5em;
    }
    10% {
        top: 0;
    }
    33% {
        top: 0;
    }
    40% {
        top: 1.5em;
    }
    100% {
        top: 1.5em;
    }
}

L'idée de l'animation est de partir depuis une position qui est au-dessus de la partie visible (top: -1.5em;), de rapidement le faire défiler sur la surface visible (top: 0;). Ensuite, on le laisse un peu sur la surface visible (le temps que des internautes puissent le lire) avant de faire le faire disparaitre, mais en dessous de l'espace visible (top: 1.5em;). Lorsque l'animation redémarrera, le sous-titre sera à nouveau caché instantanément au-dessus de la surface visible.

On applique cette animation Ă  chaque sous-titre :

.title-box > div > div {
    position: absolute;
    top: -1.5em;
    animation: subtitle-rolling 6s linear infinite;
}
Titre principal
Sous-titre 1
Sous-titre 2
Sous-titre 3

On est content, tous nos sous-titres s'animent, mais ils dĂ©filent en mĂȘme temps et toujours les uns sur les autres. Il va falloir dĂ©caler le dĂ©marrage de l'animation pour chacun. Comme je suis fainĂ©ant, je vais essayer de rendre ça un peu gĂ©nĂ©rique.

Je vais utiliser les variables CSS pour m'aider, sur chaque sous-titre, je vais dĂ©finir une variable CSS --subtitle-position qui va ĂȘtre un simple index qui va de 0 Ă  2.


<div class="title-box"> <!-- J'entoure avec cet autre div uniquement pour pouvoir le placer dans une page -->
    <h1>Titre principal</h1>
    <div> <!-- Ce div va définir l'espace visible, je l'appellerai parfois <div> encadrant -->
        <div style="--subtitle-position: 0;">Sous-titre 1</div>
        <div style="--subtitle-position: 1;">Sous-titre 2</div>
        <div style="--subtitle-position: 2;">Sous-titre 3</div>
    </div>
</div>

Je veux faire démarrer chaque sous-titre à 2s d'écart. Pour pouvoir le faire, j'ai à ma disposition la propriété animation-delay. Dans cette propriété, je vais réutiliser la variable que nous venons de définir en multipliant sa valeur par 2. Pour cette partie, le code est nettement plus parlant :

.title-box > div > div {
    position: absolute;
    top: -1.5em;
    animation: subtitle-rolling 6s linear infinite;
    animation-delay: calc(var(--subtitle-position) * 2s);
}

Ainsi, l'animation du premier sous-titre commencera immédiatement, le second commencera au bout de 1x2s et le dernier au bout de 2x2s. Et voici le résultat :

Titre principal
Sous-titre 1
Sous-titre 2
Sous-titre 3

Voilà, j'espÚre que cet article vous aura été utile pour comprendre en détail ce qui se passe sur cet effet. J'ai essayé de reproduire le cheminement qui a été le mien tout au long. N'hésitez pas à me contacter, je prends toute forme de remarque.

© Copyright 2025 - Serious Devs