Animation de la largeur et de la hauteur CSS sans l’effet Squish • PQINA


Pouvoir animer le CSS width et height les propriétés seraient super utiles. Malheureusement pour le moment, c’est un moyen infaillible de faire hurler votre navigateur à l’agonie. Dans ce didacticiel de 5 minutes, nous allons explorer l’utilisation du transform pour simuler l’animation de la largeur d’un élément.

N’animez pas les propriétés de largeur et de hauteur

Les navigateurs n’apprécient pas quand ils doivent calculer la position et la taille des éléments sur la page Web. La plupart des éléments ont un impact sur le rendu des autres éléments. La modification des dimensions d’un élément peut avoir de nombreuses conséquences imprévues.

Modification du width et / ou height d’un élément, le navigateur devra calculer quels autres éléments (enfants, frères et sœurs ou parent) sont affectés par ce changement et comment ces éléments doivent être mis à jour. Ce processus est appelé refusion et sera suivi d’une repeinture.

Ce sont des opérations coûteuses et nous devons éviter de les déclencher autant que possible.

Utilisation de Transform à la place

Pour faire des animations performantes, nous devons utiliser le CSS transform ou opacity Propriétés. Dans cet article, nous allons nous concentrer sur transform.

La propriété transform demande au GPU d’effectuer des mises à jour de dernière minute de la texture d’un élément avant de le dessiner à l’écran. Ces mises à jour de dernière minute peuvent par exemple être la rotation, le déplacement et la mise à l’échelle de l’élément.

Vous pouvez comparer la texture GPU d’un élément avec une photo que vous avez prise de l’élément avec votre téléphone portable. L’image est uniquement composée de pixels, les éléments enfants et d’autres informations sur l’élément ne sont plus là.

Le GPU n’a à gérer que les pixels qui présentent l’élément. Et parce que les GPU sont très bons pour gérer les pixels. Ces opérations de transformation sont super performantes.

Cela a également un inconvénient. Nous ne pouvons manipuler que les pixels, pas le contenu de l’élément (nous n’avons que l’image de l’élément). Vous pouvez voir ci-dessous comment cette différence affecte la border-radius propriété. dans le transform par exemple le rayon n’est pas redessiné (comme dans le width exemple), il est simplement mis à l’échelle. Redessiner nécessiterait une repeinture, le GPU ne peut pas le faire, il ne traite que des pixels.

.square {
    width: 200px;
    height: 200px;
    border-radius: 40px;
}

.square-resized { width: 100px }

.square-transformed { transform: scaleX(.5) }

Animer le transform la propriété est un million de fois plus rapide que l’animation width, height, ou toute autre propriété ayant un impact sur la mise en page et déclencher une refusion.

Mais si nous l’animons, le résultat sera cette forme étrangement étirée. Ça peut être rapide, mais ça n’a pas l’air génial. Cela me rappelle toujours ces extraterrestres dans Duke Nukem 3D écrasés par une porte.

Mise à l’échelle à 9 tranches à la rescousse

Avant border-radius était une chose que nous devions créer une image pour chaque coin (et parfois bord) d’un élément à “faux” rayon de bordure. Selon la conception qui pourrait produire jusqu’à 8 images pour un seul élément, ces images seraient disposées comme ceci.

C’est ce qu’on appelle le Méthode de mise à l’échelle à 9 tranches.

Cette méthode vous permet de mettre à l’échelle l’élément et d’étirer l’image 2, 4, 6 et 8, tout en reliant 1, 3, 7 et 9 à leurs coins respectifs en utilisant un positionnement absolu. Il en résulte des coins qui ne sont pas étirés lors de la mise à l’échelle. Voir ci-dessous.

Heureusement, nous vivons à une époque où les navigateurs prennent en charge border-radius nous n’avons donc plus à compter sur cette technique pour dessiner des coins arrondis.

On peut cependant utiliser cette technique pour redimensionner des éléments en utilisant le transform propriété.

Nous allons commencer avec une structure comme celle-ci:

Appliquons cela à notre carré. Cela signifie que nous avons besoin d’un conteneur et de trois éléments enfants pour représenter les parties carrées gauche (1), centrale (2) et droite (3).

 class="square">
     class="left">
class="center">
class="right">

Regardons le CSS

/* children will be positioned relativly to this element */
.square {
    position: relative;
    height: 100px;
}

.left,
.center,
.right {
    position: absolute;
    top: 0;
    bottom: 0;
}

.left { background: red }
.center { background: yellow }
.right { background: blue }


/* we need room for a 20 pixel border radius (on one side) */
.left,
.right { width: 20px }

.left { border-radius: 20px 0 0 20px }
.right { border-radius: 0 20px 20px 0 }


/* child layout definitions */
.center {
    /* center needs to be 20 pixels from the left, 
    so it doesn't overlap with the .left element */
    left: 20px;

    /* needs a width of 1 pixel, this causes 
    scaleX(60) is equal to 60 pixels */
    width: 1px;
    transform: scaleX(60);

    /* we need to scale the texture from the left side 
    for it to align correctly, default is center */
    transform-origin: left;
}

.right {
    /* we need to move the right element to align with
    the right side of the .center element 
    20px + 60px = 80px */
    transform: translateX(80px);
}

Le résultat est un carré joliment coloré.

J’ai coloré les éléments pour les rendre reconnaissables individuellement.

Maintenant, pour notre prochaine astuce, nous pouvons animer la .center et .right éléments du carré.

.center {
    animation: center-animate 1s ease infinite alternate;
}

.right {
    animation: right-animate 1s ease infinite alternate;
}

@keyframes right-animate {
    0% { transform: translateX(140px) }
    100% { transform: translateX(20px) }
}

@keyframes center-animate {
    0% { transform: scaleX(120) }
    100% { transform: scaleX(0) }
}

Cela me semble bien, redéfinissons la couleur d’arrière-plan sur le noir.

Si vous êtes sur Firefox, cela devrait être parfait. Si vous utilisez Safari ou Chrome, vous remarquerez peut-être un léger scintillement du bord entre la partie centrale et la partie droite.

Je ne sais pas pourquoi cela se produit. C’est soit un problème de mélange alpha OU d’arrondi de pixels. En tous cas. En chevauchant légèrement l’élément central avec l’élément droit, nous pouvons résoudre ce problème de rendu. Nous nous assurerons que l’élément est au moins 1 pixel large et évolue vers 121 pixels.

@keyframes center-animate {
    0% { transform: scaleX(121) }
    100% { transform: scaleX(1) }
}

Vive! Nous nous sommes procuré un carré non squishy animable!

Nous pourrions aller plus loin et le rendre plus flexible en déplaçant l’animation vers JavaScript, en créant un composant Web ou en utilisant des variables CSS, mais pour les besoins de cet article, cet exemple devrait suffire.

Voir une démo du résultat final sur CodePen

Calmez-vous

Avant de commencer et d’utiliser cette technique, veuillez noter que:

  • Les images d’arrière-plan du carré seront étirées, car nous mettons à l’échelle le carré central sur l’axe X.
  • UNE box-shadow peut être fait mais est un peu difficile à réaliser.
  • Le carré ne peut pas couper d’autres éléments, comme dans, overflow: hidden ne fonctionnera pas.

Cela dit, avec un peu de ruse, vous pouvez l’utiliser pour créer des effets impressionnants. Les éléments de fichier et la zone de dépôt de la bibliothèque de téléchargement de fichiers FilePond utilisent tous cette technique pour animer en douceur leur hauteur.

Une version précédente de Doka Image Editor utilisait cette technique à la fois sur la largeur et la hauteur pour rendre et animer le rectangle de recadrage blanc au-dessus de l’image. Depuis, il a été partiellement remplacé par WebGL.

Conclusion

Le défaut width et height Les propriétés CSS ne conviennent pas (comme la plupart des autres propriétés) à l’animation. Ils impactent trop les performances de rendu.

Nous sommes passés au transform et a animé notre carré sur le GPU pour améliorer considérablement les performances, mais s’est retrouvé avec d’autres limitations (coins carrés squishy).

En appliquant la technique des 9 tranches d’une manière intelligente, nous avons contourné certaines de ces limitations pour créer un élément que nous pouvons animer sans affecter les performances.

Close Menu