Fermer

avril 2, 2024

Logos à défilement infini en HTML plat et CSS pur

Logos à défilement infini en HTML plat et CSS pur


Rappelez-vous le HTML <marquee> élément? Il est obsolète, ce n’est donc pas comme si vous alliez l’utiliser lorsque vous avez besoin d’une sorte de fonction de défilement automatique horizontal. C’est là que CSS entre en jeu car il dispose de tous les outils dont nous avons besoin pour y parvenir. Sivestar Bistrović démontre une technique qui rend cela possible avec un ensemble d’images et le moins de HTML possible.

Lorsqu’on m’a demandé de créer une ferme de logos à défilement automatique, j’ai dû me demander : « Vous voulez dire, comme un <marquee>? » Ce n’est pas la demande la plus étrange, mais la pensée d’un <marquee> évoque l’« ancienne » époque du Web lorsque Geocities régnait. Quelle était la prochaine étape, un arrière-plan GIF de licorne scintillant et répétitif ?

Si vous êtes tenté d’atteindre le <marquee> élément, ne le faites pas. MDN a un avertissement sévère à ce sujet juste en haut de la page:

« Obsolète : Cette fonctionnalité n’est plus recommandée. Bien que certains navigateurs puissent encore le prendre en charge, il se peut qu’il ait déjà été supprimé des normes Web pertinentes, qu’il soit en train de l’être ou qu’il ne soit conservé qu’à des fins de compatibilité. Évitez de l’utiliser et mettez à jour le code existant si possible […] Sachez que cette fonctionnalité peut cesser de fonctionner à tout moment.

C’est bien parce que quelle que soit la fonctionnalité de défilement infini <marquee> est proposé, nous pouvons très certainement réussir en CSS. Mais lorsque j’ai recherché des exemples pour me guider, j’ai été surpris de trouver très peu de choses à ce sujet. Peut-être que les éléments à défilement automatique ne font pas fureur de nos jours. Peut-être que la nature même du comportement de défilement automatique est suffisamment un signal d’alarme en matière d’accessibilité pour nous effrayer.

Quoi qu’il en soit, nous avons les outils pour le faire, et je voulais partager comment j’ai procédé. C’est l’une de ces choses qui peuvent être réalisées de nombreuses manières différentes, en tirant parti de nombreuses fonctionnalités CSS différentes. Même si je ne vais pas les explorer tous de manière exhaustive, je pense qu’il est intéressant de voir le processus de pensée de quelqu’un d’autre, et c’est ce que vous allez obtenir de moi dans cet article.

Ce que nous faisons

Mais d’abord, voici un exemple du résultat final :

Voir le stylo [CSS only marquee without HTML duplication [forked]](https://codepen.io/smashingmag/pen/YzMQMXe) par Sylvester Bistrović.

Voir le stylo Marquee CSS uniquement sans duplication HTML [forked] par Sylvester Bistrović.

L’idée est assez simple. Nous voulons une sorte de conteneur, et à l’intérieur, nous voulons une série d’images qui défilent à l’infini. En d’autres termes, lorsque la dernière image glisse, nous voulons que la première image de la série la suive directement dans une boucle infinie.

Alors voici le plan : Nous allons d’abord configurer le code HTML, puis choisir le conteneur et nous assurer que les images y sont correctement positionnées avant de passer à l’écriture de l’animation CSS qui rassemble le tout.

Exemples existants

Comme je l’ai mentionné, j’ai essayé de chercher des idées. Même si je n’ai pas trouvé exactement ce que je cherchais, j’ai trouvé quelques démos qui m’ont fourni une étincelle d’inspiration. Ce que je voulais vraiment, c’était utiliser uniquement CSS sans avoir à « cloner » les éléments de sélection.

« Effet de fond coulissant» est proche de ce que je voulais. Bien qu’il soit daté, cela m’a aidé à voir comment je pouvais intentionnellement utiliser overflow pour permettre aux images de « glisser » hors du conteneur et à une animation qui tourne en boucle pour toujours. Il s’agit cependant d’une image d’arrière-plan qui repose sur des valeurs numériques très spécifiques qui rendent difficile sa réutilisation dans d’autres projets.

Voir le stylo [Untitled [forked]](https://codepen.io/smashingmag/pen/LYvLvGz) par @ astuces-css.

Voir le stylo Sans titre [forked] par @ astuces-css.

Il y a un autre excellent exemple de Parcours de codage chez CodePen :

Voir le stylo [Marquee-like Content Scrolling [forked]](https://codepen.io/smashingmag/pen/yLrXrVY) par Parcours de codage.

Voir le stylo Défilement de contenu de type chapiteau [forked] par Parcours de codage.

L’effet est certainement ce que je recherche, mais il utilise du JavaScript, et même s’il ne s’agit que d’une légère pincée, je préférerais laisser JavaScript en dehors du mélange.

« » de Ryan MulliganMur de logos CSS Marquee» est la chose la plus proche. Non seulement il s’agit d’une ferme de logos avec des images individuelles, mais elle montre comment le masquage CSS peut être utilisé pour masquer les images lorsqu’elles glissent dans et hors du conteneur. J’ai pu intégrer cette même idée dans mon travail.

Voir le stylo [CSS Marquee Logo Wall [forked]](https://codepen.io/smashingmag/pen/ExJXJZm) par Ryan Mulligan.

Voir le stylo Mur de logos CSS Marquee [forked] par Ryan Mulligan.

Mais il y a encore autre chose que je recherche. Ce que je voudrais, c’est la plus petite quantité de HTML possible, c’est-à-dire un balisage qui n’a pas besoin d’être dupliqué pour donner l’impression qu’il existe un nombre infini d’images. En d’autres termes, nous devrions être capables de créer une série d’images à défilement infini où les images sont les seuls éléments enfants du conteneur « chapiteau ».

J’ai trouvé quelques exemples supplémentaires ailleurs, mais ceux-ci ont suffi à m’orienter dans la bonne direction. Suivez-moi.

Le HTML

Configurons la structure HTML avant toute autre chose. Encore une fois, je veux que cela soit aussi « simple » que possible, c’est-à-dire très peu d’éléments avec l’arbre généalogique le plus court possible. Nous ne pouvons nous contenter que du conteneur « chapiteau » et des images du logo qu’il contient.

<figure class="marquee">
  <img class="marquee__item" src="https://smashingmagazine.com/2024/04/infinite-scrolling-logos-html-css/logo-1.png" width="100" height="100" alt="Company 1">
  <img class="marquee__item" src="logo-2.png" width="100" height="100" alt="Company 2">
  <img class="marquee__item" src="logo-3.png" width="100" height="100" alt="Company 3">
</figure>

Cela permet de garder les choses aussi « plates » que possible. Il ne devrait y avoir rien d’autre dont nous ayons besoin ici pour que les choses fonctionnent.

Configuration du conteneur

Flexbox pourrait être l’approche la plus simple pour établir une rangée d’images avec un espace entre elles. Nous n’avons même pas besoin de lui dire de s’écouler dans le sens d’une ligne car c’est la valeur par défaut.

.marquee {
  display: flex;
}

Je sais déjà que je prévois d’utiliser le positionnement absolu sur les éléments de l’image, il est donc logique de définir le positionnement relatif sur le conteneur pour, vous savez, contenir eux. Et comme les images sont dans une position absolue, elles n’ont pas de dimensions réservées en hauteur ou en largeur qui influencent la taille du conteneur. Nous devrons donc déclarer un explicite block-size (l’équivalent logique de height). Nous avons également besoin d’une largeur maximale afin d’avoir une limite pour que les images puissent glisser vers l’intérieur et l’extérieur de la vue, nous utiliserons donc max-inline-size (l’équivalent logique de max-width) :

.marquee {
  --marquee-max-width: 90vw;

  display: flex;
  block-size: var(--marquee-item-height);
  max-inline-size: var(--marquee-max-width);
  position: relative;
}

Remarquez que j’utilise quelques variables CSS : une qui définit la hauteur du chapiteau en fonction de la hauteur de l’une des images (--marquee-item-height) et celui qui définit la largeur maximale du chapiteau (--marquee-max-width). Nous pouvons maintenant donner une valeur à la largeur maximale du chapiteau, mais nous devrons formellement enregistrer et attribuer une valeur à la hauteur de l’image, ce que nous ferons dans un instant. J’aime juste savoir avec quelles variables je prévois de travailler au fur et à mesure.

Ensuite, nous voulons que les images soient masquées lorsqu’elles se trouvent à l’extérieur du conteneur. Nous allons définir le débordement horizontal en conséquence :

.marquee {
  --marquee-max-width: 90vw;

  display: flex;
  block-size: var(--marquee-item-height);
  max-inline-size: var(--marquee-max-width);
  overflow-x: hidden;
  position: relative;
}

Et moi vraiment comme la façon dont Ryan Mulligan a utilisé un masque CSS. Cela crée l’impression que les images apparaissent et disparaissent. Alors, ajoutons cela au mélange :

.marquee {
  display: flex;
  block-size: var(--marquee-item-height);
  max-inline-size: var(--marquee-max-width);
  overflow-x: hidden;
  position: relative;
  mask-image: linear-gradient(
    to right,
    hsl(0 0% 0% / 0),
    hsl(0 0% 0% / 1) 20%,
    hsl(0 0% 0% / 1) 80%,
    hsl(0 0% 0% / 0)
  );
  position: relative;
}

Voici ce que nous avons jusqu’à présent :

Voir le stylo [CSS only marquee without HTML duplication, example 0 [forked]](https://codepen.io/smashingmag/pen/LYvjLLG) par Sylvester Bistrović.

Voir le stylo Marquee CSS uniquement sans duplication HTML, exemple 0 [forked] par Sylvester Bistrović.

Positionnement des éléments de sélection

Le positionnement absolu est ce qui nous permet de retirer les images du flux de documents et de les positionner manuellement afin que nous puissions commencer par là.

.marquee__item {
  position: absolute;
}

Cela donne l’impression que les images ont complètement disparu. Mais ils sont là : les images sont empilées directement les unes sur les autres.

N’oubliez pas cette variable CSS pour notre conteneur, --marquee-item-height? Maintenant, nous pouvons l’utiliser pour faire correspondre la hauteur de l’élément de sélection :

.marquee__item {
  position: absolute;
  inset-inline-start: var(--marquee-item-offset);
}

Pour pousser les images de sélection en dehors du conteneur, nous devons définir un --marquee-item-offset, mais ce calcul n’est pas trivial, nous apprendrons donc comment le faire dans la section suivante. Nous savons ce que animation doit être : quelque chose qui se déplace linéairement pendant une certaine durée après un délai initial, puis continue indéfiniment. Insérons cela avec quelques variables comme espaces réservés temporaires.

.marquee__item {
  position: absolute;
  inset-inline-start: var(--marquee-item-offset);
  animation: go linear var(--marquee-duration) var(--marquee-delay, 0s) infinite;
}

Pour animer les éléments de sélection à l’infini, nous devons définir deux variables CSS, une pour la durée (--marquee-duration) et un pour le retard (--marquee-delay). La durée peut être de n’importe quelle durée, mais le délai doit être calculé, c’est ce que nous découvrirons dans la section suivante.

.marquee__item {
  position: absolute;
  inset-inline-start: var(--marquee-item-offset);
  animation: go linear var(--marquee-duration) var(--marquee-delay, 0s) infinite;
  transform: translateX(-50%);
}

Enfin, nous traduirons l’élément de sélection par -50% horizontalement. Ce petit « hack » gère les situations dans lesquelles les tailles d’image sont inégales.

Voir le stylo [CSS only marquee without HTML duplication, example 2 [forked]](https://codepen.io/smashingmag/pen/ExJXJMQ) par Sylvester Bistrović.

Voir le stylo Marquee CSS uniquement sans duplication HTML, exemple 2 [forked] par Sylvester Bistrović.

Animer les images

Pour que l’animation fonctionne, nous avons besoin des informations suivantes :

  • Largeur des logos,
  • Hauteur des logos,
  • Nombre d’articles, et
  • Durée de l’animation.

Utilisons les configurations suivantes pour notre ensemble de variables :

.marquee--8 {
  --marquee-item-width: 100px;
  --marquee-item-height: 100px;
  --marquee-duration: 36s;
  --marquee-items: 8;
}

Note: J’utilise le modificateur BEM .marquee--8 pour définir l’animation des huit logos. Nous pouvons définir les images clés de l’animation maintenant que nous connaissons les --marquee-item-width valeur.

@keyframes go {
  to {
    inset-inline-start: calc(var(--marquee-item-width) * -1);
  }
}

L’animation déplace l’élément de sélection de droite à gauche, permettant à chacun d’être visible depuis la droite lorsqu’il se déplace hors de vue sur le bord gauche et à l’extérieur du conteneur de sélection.

Il nous faut maintenant définir le --marquee-item-offset. Nous voulons pousser l’élément de sélection complètement vers la droite du conteneur de sélection, à l’opposé de l’état final de l’animation.

Vous pourriez penser que le décalage devrait être 100% + var(--marquee-item-width), mais cela ferait chevaucher les logos sur des écrans plus petits. Pour éviter cela, nous devons connaître la largeur minimale de tous les logos combinés. Nous procédons de la manière suivante :

calc(var(--marquee-item-width) * var(--marquee-items))

Mais ce n’est pas assez. Si le conteneur de sélection est trop grand, les logos prendront moins que l’espace maximum et le décalage se fera à l’intérieur du conteneur, ce qui rendra les logos visibles à l’intérieur du conteneur de sélection. Pour éviter cela, nous utiliserons le max() fonctionner comme suit :

--marquee-item-offset: max(
  calc(var(--marquee-item-width) * var(--marquee-items)),
  calc(100% + var(--marquee-item-width))
);

Le max() La fonction vérifie laquelle des deux valeurs de ses arguments est la plus grande, la largeur totale de tous les logos ou la largeur maximale du conteneur plus la largeur du logo unique, que nous avons définie précédemment. Ce dernier sera vrai sur des écrans plus grands et le premier sur des écrans plus petits.

Voir le stylo [CSS only marquee without HTML duplication, example 3 [forked]](https://codepen.io/smashingmag/pen/BaEZEXN) par Sylvester Bistrović.

Voir le stylo Marquee CSS uniquement sans duplication HTML, exemple 3 [forked] par Sylvester Bistrović.

Enfin, nous définirons le délai d’animation compliqué (--marquee-delay) avec cette formule :

--marquee-delay: calc(var(--marquee-duration) / var(--marquee-items) * (var(--marquee-items) - var(--marquee-item-index)) * -1);

Le délai est égal à la durée de l’animation divisée par un polynôme quadratique (c’est du moins ce que me dit ChatGPT). Le polynôme quadratique est la partie suivante, où nous multiplions le nombre d’éléments par le nombre d’éléments moins l’indice d’élément actuel :

var(--marquee-items) * (var(--marquee-items) - var(--marquee-item-index))

Notez que nous utilisons un délai négatif (* -1) pour que l’animation démarre dans le « passé », pour ainsi dire. La seule variable restant à définir est la --marquee-item-index (la position actuelle de l’élément de sélection) :

.marquee--8 .marquee__item:nth-of-type(1) {
  --marquee-item-index: 1;
}
.marquee--8 .marquee__item:nth-of-type(2) {
  --marquee-item-index: 2;
}

/* etc. */

.marquee--8 .marquee__item:nth-of-type(8) {
  --marquee-item-index: 8;
}

Voici à nouveau cette démo finale :

Voir le stylo [CSS only marquee without HTML duplication [forked]](https://codepen.io/smashingmag/pen/xxerNKz) par Sylvester Bistrović.

Voir le stylo Marquee CSS uniquement sans duplication HTML [forked] par Sylvester Bistrović.

Améliorations

Cette solution pourrait être meilleure, surtout lorsque les logos n’ont pas la même largeur. Pour ajuster les écarts entre des images de tailles incohérentes, nous pourrions calculer plus précisément le retard de l’animation. C’est possible car l’animation est linéaire. J’ai essayé de trouver une formule, mais je pense qu’elle doit être peaufinée, comme vous pouvez le constater :

Voir le stylo [CSS only marquee without HTML duplication, example 4 [forked]](https://codepen.io/smashingmag/pen/NWmgVWN) par Sylvester Bistrović.

Voir le stylo Marquee CSS uniquement sans duplication HTML, exemple 4 [forked] par Sylvester Bistrović.

Une autre amélioration que nous pouvons obtenir avec un peu de réglage est d’éviter de gros écarts sur les écrans larges. Pour ce faire, définissez le max-inline-size et déclarer margin-inline: auto sur le .marquee récipient:

Voir le stylo [CSS only marquee without HTML duplication, example 5 [forked]](https://codepen.io/smashingmag/pen/qBwjGBJ) par Sylvester Bistrović.

Voir le stylo Marquee CSS uniquement sans duplication HTML, exemple 5 [forked] par Sylvester Bistrović.

Conclusion

Qu’en penses-tu? Est-ce quelque chose que vous vous voyez utiliser sur un projet ? L’aborderiez-vous différemment ? Je suis toujours heureux lorsque j’arrive sur quelque chose avec une structure HTML propre et une solution CSS pure. Vous pouvez voir la mise en œuvre finale sur le Site Heyflow.

Lectures complémentaires sur SmashingMag

Éditorial fracassant
(gg, ouais)




Source link