Leçons tirées de soixante jours de réanimation de zombies avec CSS codé à la main

Online Coding Courses for Kids

Mise en garde: Terrible sens de l’humour à venir. Nous allons parler de choses pratiques, mais les exemples impliquent presque tous des zombies et des blagues idiotes. Tu étais prévenu.

Je vais créer un lien vers des stylos individuels tout en discutant des leçons que j’ai apprises, mais si vous souhaitez avoir une idée de l’ensemble du projet, consultez 60 jours d’animation sur Undead Institute. J’ai commencé ce projet pour se terminer le 1er août 2020, coïncidant avec la publication d’un livre que j’ai écrit avec des animations CSS, de l’humour et des zombies – car, évidemment, les zombies détruiront le monde si vous ne brandissez pas vos compétences Web et arrêtez l’Apocalypse. Rien ne fait plus mal à la horde qu’un élément HTML en mouvement!

J’avais quelques règles pour moi tout au long du projet.

  1. Je coderais à la main tous les CSS. (Je suis masochiste.)
  2. L’utilisateur lancerait toute l’animation. (Je déteste tomber sur une animation qui est déjà à mi-chemin.)
  3. J’utiliserais le moins possible JavaScript et jamais pour l’animation. (Je n’ai fini par utiliser JavaScript qu’une seule fois, et c’était pour démarrer l’audio avec l’animation finale. Je n’ai rien contre JavaScript, ce n’est tout simplement pas ce que je voulais faire ici.)

Leçon 1: Quatre-vingts jours, c’est long.

Euh, le titre ne dit-il pas «soixante» jours? Oui, mais mon objectif initial était de faire quatre-vingts jours et à l’approche du premier jour avec moins de vingt animations préparées et une moyenne de trois jours pour chaque production, j’ai paniqué et je suis passé à soixante jours. Cela m’a donné à la fois vingt jours de plus jusqu’à la date de début et vingt pièces de moins à faire.

Leçon 1A: Soixante jours, c’est encore un long moment.

C’est beaucoup d’animation à faire avec un temps limité, des idées et des compétences artistiques encore plus limitées. Et pendant que je pensais passer à trente jours, je suis content de ne pas l’avoir fait. Soixante jours m’ont étiré et m’ont obligé à approfondir le fonctionnement de l’animation CSS – et par extension, CSS lui-même. Je suis aussi le plus fier de plusieurs des dernières pièces que j’ai faites au fur et à mesure que mes compétences augmentaient, et je devais être plus innovant et réfléchir davantage à la façon de rendre les choses intéressantes. Une fois que vous avez utilisé toutes les options simples, le travail réel et les meilleurs résultats commencent. (Et oui, cela a duré soixante-deux jours parce que j’ai commencé le 1er juin et que je voulais faire une dernière animation le 1er août. À partir du 3 juin, je me sentais juste dégoûtant.)

Donc, la vraie leçon 1: étirez-vous.

Leçon 2: Les animations interactives sont difficiles, et encore plus difficiles à rendre réactives.

Si vous voulez que quelque chose vole à travers l’écran et se connecte à un autre élément ou semble commencer le déplacement d’un autre élément, vous devez utiliser toutes les unités standard, rigides ou toutes les unités flexibles.

Trois variables déterminent quand et où un élément animé se trouvera pendant une animation: durée, vitesse et distance. La durée de l’animation est définie dans la propriété animation et ne peut pas être modifiée en fonction de la taille de l’écran. La fonction de synchronisation d’animation détermine la vitesse; la taille de l’écran ne peut pas non plus changer cela. Ainsi, si la distance varie avec la taille de l’écran, la synchronisation sera désactivée partout sauf une largeur et une hauteur d’écran spécifiques.

Regarder Réservoir!. Exécutez l’animation sur des écrans larges et étroits. Bien que le timing soit proche, si vous comparez les deux, vous verrez que le tank est à un endroit différent par rapport aux zombies lorsque les derniers zombies tombent.

Montrant la même prise brune, côte à côte, où le réservoir sur la gauche est plus loin que le réservoir sur la droite.

Pour éviter ces problèmes de synchronisation, vous pouvez utiliser des unités fixes et un grand nombre, comme 2000 ou 5000 pixels ou plus, de sorte que l’animation couvre la largeur (ou la hauteur) de l’écran pour tous les moniteurs sauf les plus grands.

Leçon 3: Si vous souhaitez une animation réactive, mettez tout dans (l’une des) unités de fenêtre.

Faire des demi-tours sur les proportions des unités (par exemple, définir la largeur et la hauteur en pixels, mais l’emplacement et le mouvement avec les unités de la fenêtre) entraînera des résultats imprévisibles. N’utilisez pas à la fois vw et vh mais l’un ou l’autre; quelle que soit l’orientation dominante. Mélanger des unités vh et vw rendra votre animation «bancale», ce qui, je crois, est le terme technique.

Prendre Superbement zomborrifique, par exemple. Il mélange des unités pixel, vw et vh. Le principe est que le Super Zombie vole vers le haut alors que la «caméra» suit. Super Zombie s’écrase sur un rebord et tombe alors que la caméra continue, mais vous ne le comprendriez pas si votre écran était suffisamment haut.

Deux images d'animation, côte à côte où la gauche montre le zombie vert volant frappant le plafond d'un bâtiment et la droite montre le zombie quittant l'image après l'impact.

Cela signifie également que si vous avez besoin que quelque chose vienne du haut – comme je l’ai fait Personne ici mais nous les humains —Vous devez régler la hauteur vw suffisamment élevée pour vous assurer que le zombie ninja ne soit pas visible dans la plupart des proportions.

Leçon 3A: Utiliser des unités de pixels pour les mouvements dans un élément SVG.

Cela dit, la transformation d’éléments dans un élément SVG ne doit pas utiliser des unités de fenêtre. Les balises SVG sont leur propre univers proportionnel. Le “pixel” SVG restera proportionnel dans l’élément SVG à tous les autres enfants d’élément SVG alors que les unités de fenêtre ne le seront pas. Transformez donc avec des unités de pixels dans un élément SVG, mais utilisez des unités de fenêtre partout ailleurs.

Leçon 4: Les SVG évoluent horriblement à l’exécution.

Pour les animations, comme Oups…, J’ai rendu l’image SVG de l’échelle zombie jusqu’à cinq fois sa taille, mais cela rend les bords flous. [Shakes fist at “scalable” vector graphics.]

/* Original code resulting in fuzzy edges */
.zombie {
  transform: scale(1);
  width: 15vw;
}

.toggle-checkbox:checked ~ .zombie {
  animation: 5s ease-in-out 0s reverseshrinkydink forwards;
}

@keyframes reverseshrinkydink {
  0% {
    transform: scale(1);
  }
  100% {
    transform: scale(5);
  }
}

J’ai appris à définir leurs dimensions sur les dimensions finales qui seraient en vigueur à la fin de l’animation, puis à utiliser une transformation d’échelle pour les réduire à la taille du début de l’animation.

/* Revised code */
.zombie {
  transform: scale(0.2);
  width: 75vw;
}

.toggle-checkbox:checked ~ .zombie {
  animation: 5s ease-in-out 0s reverseshrinkydink forwards;
}

@keyframes reverseshrinkydink {
  0% {
    transform: scale(0.2);
  }
  100% {
    transform: scale(1);
  }
}

En bref, le code révisé passe d’une version réduite de l’image à la largeur et à la hauteur complètes. Le navigateur rend toujours à 1, ce qui rend les bords nets et nets à une échelle de 1. Donc, au lieu de mettre à l’échelle de 1 à 5, j’ai mis à l’échelle de 0,2 à 1.

Le même cadre d'animation d'un scientifique tenant une tasse de café debout à gauche d'un zombie en croissance où le cadre de gauche montre le zombie avec des bords flous et le cadre de droite est clair.

Leçon 5: L’axe n’est pas une vérité universelle.

Les axes d’un élément restent synchronisés avec l’élément, pas avec la page. Une rotation de 90 degrés avant une translateX changera la direction du translateX de l’horizontale à la verticale. Dans Personne ici mais nous les humains… 2, J’ai retourné les zombies en utilisant une rotation de 180 degrés. Mais les valeurs Y positives déplacent les ninjas vers le haut et les valeurs négatives les déplacent vers le bas (le contraire de la normale). Méfiez-vous de la façon dont une rotation peut affecter les transformations plus loin sur la ligne.

Montrant le personnage principal face à nous au premier plan avec 7 personnages ninja suspendus à l'envers du plafond sur un fond rose clair.

Leçon 6. Séparez les animations complexes en éléments concentriques pour faciliter les ajustements.

Lors de la création d’une animation complexe qui se déplace dans plusieurs directions, ajouter des divs wrapper, ou plutôt des éléments parents, et animer chacun d’eux individuellement réduira les transformations conflictuelles et vous évitera de devenir un désordre pleureur.

Par exemple, dans Cadet de l’espace, J’ai eu trois transformations différentes en cours. Le premier est le mouvement du zomb-o-naut dans un mouvement de haut en bas. Le second est un mouvement à travers l’écran. Le troisième est une rotation. Plutôt que d’essayer de tout faire en une seule transformation, j’ai ajouté deux éléments d’emballage et fait une animation sur chaque élément (j’ai également sauvé mes cheveux … au moins une partie.) Cela a permis d’éviter les problèmes d’axe discutés dans la dernière leçon car je a effectué la rotation sur l’élément le plus intérieur, laissant les axes de ses parents et grands-parents en place.

Leçon 7: Les transformations SVG et CSS sont les mêmes.

Certains chemins et groupes et autres éléments SVG auront déjà des transformations définies sur eux. Cela peut provenir d’un algorithme d’optimisation ou peut-être simplement de la manière dont le logiciel d’illustration génère le code. Si un chemin, un groupe ou tout autre élément d’un SVG a déjà une transformation SVG, la suppression de cette transformation réinitialisera l’élément, souvent à un emplacement ou une taille bizarre par rapport au reste du dessin.

Étant donné que les transformations SVG et CSS sont les mêmes, toute transformation CSS que vous effectuez remplace la transformation SVG, ce qui signifie que votre transformation CSS commencera à partir de cet emplacement ou de cette taille bizarre plutôt que de l’emplacement ou de la taille défini dans le SVG.

Vous pouvez copier la transformation de l’élément SVG vers votre CSS et la définir comme position de départ dans CSS (en la mettant d’abord à jour avec la syntaxe CSS, bien sûr). Vous pouvez ensuite le modifier dans votre animation CSS.

Par exemple, dans Euh, ouais…, mon hommage à Espace de bureau, Le bras supérieur droit de Undead Lumbergh (l’élément # arm2) avait une transformation dans le code SVG d’origine.

Une comparaison côte à côte d'un zombie vêtu d'une chemise boutonnée bleue et de bretelles noires tout en tenant une tasse de café. Sur la gauche, le bras tenant les tasses à café dans la bonne position mais la droite montre le bras détaché du corps.

Déplacer cette transformation vers CSS comme ceci:

#arm2 {
  transform: translate(0, -343px) scale(4, 3.55);
}

… Je pourrais alors créer une animation qui ne réinitialise pas accidentellement l’emplacement et l’échelle:

.toggle-checkbox:checked ~ .z #arm2 { 
  animation: 6s ease-in-out 0.15s arm2move forwards;
}

@keyframes arm2move {
  0%, 100% {
    transform: translate(0, -343px) scale(4, 3.55);
  }
  40%, 60% {
    transform: translate(0, -403px) scale(4, 3.55);
  }
  50% {
    transform: translate(0, -408px) scale(4, 3.55);
  }
} 

Ce processus est plus difficile lorsque l’outil générant le code SVG tente de «simplifier» la transformation en matrice. Bien que vous puissiez recréer la transformation matricielle en la copiant dans le CSS, c’est une tâche difficile à faire. Vous êtes un meilleur développeur que moi – ce qui peut être vrai de toute façon – si vous pouvez prendre une transformation matricielle et la manipuler pour la mettre à l’échelle, la faire pivoter ou la traduire exactement comme vous le souhaitez.

Vous pouvez également recréer la transformation matricielle à l’aide de la translation, de la rotation et de la mise à l’échelle, mais si le chemin est complexe, la probabilité que vous puissiez le recréer en temps opportun sans vous retrouver dans une veste droite est faible.

La dernière option et probablement la plus simple consiste à envelopper l’élément dans un groupe (). Ajoutez-y une classe ou un ID pour un accès CSS facile et transformez le groupe lui-même, séparant ainsi les transformations comme indiqué dans la dernière leçon.

Leçon 8: Gardez votre santé mentale en utilisant transform-origin lors de la transformation d’une partie d’un SVG

Le CSS transform-origin property déplace le point autour duquel la transformation se produit. Si vous essayez de faire pivoter un bras – comme je l’ai fait dans Clubbin ’It – votre animation paraîtra plus naturelle si vous faites pivoter le bras à partir du centre de l’épaule, mais l’origine naturelle de la transformation de ce chemin se trouve en haut à gauche. Utilisation transform-origin pour résoudre ce problème pour une sensation plus douce et plus naturelle … vous le savez vraiment Naturel aspect pixel art…

Quatre images séquentielles d'une animation montrant un personnage d'homme des cavernes tourné vers la gauche, tenant un grand club en bois et le soulevant du bas vers l'arrière de sa tête.

La transformation de l’origine peut également être utile lors de la mise à l’échelle, comme je l’ai fait dans Oups moustachu, ou lors de la rotation des mouvements de la bouche, comme la mâchoire du dinosaure Super savoureux. Si vous ne modifiez pas l’origine, les transformations utiliseront un point d’origine dans le coin supérieur gauche de l’élément SVG.

Leçon 9: Les animations de sprites peuvent être réactives

J’ai fini par faire beaucoup d’animations de sprite pour ce projet (c’est-à-dire où vous utilisez plusieurs images incrémentielles et passez de l’une à l’autre assez rapidement pour que les personnages semblent bouger). J’ai créé les images dans un seul fichier large, je les ai ajoutées comme image d’arrière-plan à un élément de la taille d’un seul cadre, utilisé background-size pour définir l’image d’arrière-plan sur la largeur de l’image et masquer le débordement. Puis j’ai utilisé background-position et la fonction de minutage d’animation, step(), pour parcourir les images; par exemple: Célébrations post-apocalyptiques.

Avant le projet, j’ai toujours utilisé des images inflexibles. Je réduirais un peu les choses pour qu’il y ait au moins un peu de réactivité, mais je ne pensais pas que vous pouviez en faire une largeur entièrement flexible. Cependant, si vous utilisez SVG comme image d’arrière-plan, vous pouvez ensuite utiliser les unités de la fenêtre pour mettre à l’échelle l’élément avec la taille de l’écran changeante. Le seul problème est la position de l’arrière-plan. Cependant, si vous utilisez des unités de fenêtre pour cela, elles resteront synchronisées. Vérifiez cela dans Enfin, seul avec mon sandwich…

Leçon 9A: Utiliser les unités de la fenêtre pour définir la taille d’arrière-plan d’une image lors de la création d’une animation sprite réactive

Comme je l’ai appris tout au long de ce projet, l’utilisation d’un seul type d’unité est presque toujours la solution. Au départ, je définissais la taille d’arrière-plan de mon sprite à l’aide de pourcentages. Le calcul était facile (100% * (number of steps + 1)) et cela a bien fonctionné dans la plupart des cas. Dans les animations plus longues, cependant, le suivi d’image exact peut être désactivé et des parties de la mauvaise image de sprite peuvent s’afficher. Le problème s’aggrave à mesure que de plus en plus d’images sont ajoutées au sprite.

Je ne suis pas sûr de la raison exacte pour laquelle cela pose un problème, mais je pense que c’est à cause des erreurs d’arrondi qui s’aggravent sur la longueur de la feuille de sprite (la quantité de décalage augmente avec le nombre d’images).

Pour ma dernière animation, Ce n’est pas fini tant que le zombie ne chante pas, J’ai eu un dinosaure ouvert la bouche pour révéler un chant de zombie Viking (alors que des lasers tiraient en arrière-plan et qu’il y avait de la danse, des accordéons et des zombies tirés de canons, bien sûr). Ouais, je sais comment organiser une fête… une fête de nerd.

Le dinosaure et le viking étaient l’une des plus longues animations de sprites que j’ai faites pour le projet. Mais lorsque j’utilisais des pourcentages pour définir la taille de l’arrière-plan, le suivi était désactivé à certaines tailles dans Safari. À la fin de l’animation, une partie du nez du dinosaure d’une image différente apparaîtrait à droite et une partie similaire du nez serait manquante à gauche.

Un grand dinosaure vert derrière une foule de personnes, toutes tournées vers l'avenir.
Le dinosaure de gauche manque une partie de sa joue gauche et il en pousse une nouvelle à côté de sa joue droite.

C’était très frustrant à diagnostiquer car cela semblait fonctionner correctement dans Chrome et je pense que je l’ai corrigé dans Safari uniquement pour regarder une taille d’écran légèrement différente et voir à nouveau le cadre. Cependant, si j’utilisais des unités cohérentes – c’est-à-dire vw pour background-size, largeur du cadre et background-position – tout a bien fonctionné. Encore une fois, il s’agit de travailler avec des unités cohérentes!

Leçon 10: Invitez des personnes à participer au projet.

Une foule de 32 personnages pixel-art des démos précédentes face à l'écran.

Alors que j’ai appris des tonnes de choses au cours de ce processus, je me suis cogné la tête contre le mur pour la plupart (souvent jusqu’à ce que le mur se brise ou que ma tête le fasse… je ne peux pas le dire). Bien que ce soit une façon de le faire, même si vous avez la tête dure, vous vous retrouverez toujours avec un mal de tête. Invitez d’autres personnes à participer à votre projet, que ce soit pour obtenir des conseils, pour signaler un angle mort évident que vous avez manqué, fournir des commentaires, vous aider avec le projet ou simplement vous encourager à continuer lorsque la portée est stupidement et arbitrairement grande.

Alors laissez-moi mettre cette leçon en pratique. Quelles sont vos pensées? Comment allez-vous arrêter les hordes de zombies avec l’animation CSS? Quel projet stupidement et arbitrairement grand allez-vous entreprendre pour vous étirer?

Close Menu