• 15 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 2/7/24

Créez des animations fluides avec la propriété CSS transform

Pour nous assurer que nos animations soient aussi fluides que possibles, nos deux propriétés alliées sont  transform  et  opacity. Seulement deux propriétés, ça vous paraît limité ?

Détrompez-vous ! Car elles nous permettent en réalité de réaliser une multitude d'effets d'animation.

Découvrez le potentiel de transform

La propriété  transform  s'avère un véritable couteau suisse en termes d'animation. En effet, elle dispose de plus de 20 fonctions différentes pour déplacer, faire pivoter, déformer et changer la taille des éléments.

Dans les chapitres précédents, nous avons utilisé  transform  pour modifier la taille d’un bouton et d’un cercle. Nous connaissons donc sa syntaxe et sa fonction   scale().

.btn {
    :hover + .ball{
        transform: scale(1);    
    }   
}            

Mais pour exploiter toute la puissance de la propriété transform, nous allons commencer à utiliser plusieurs de ses fonctions. Dans ce chapitre, nous allons couvrir les fonctions  transform  les plus utiles, et voir comment les lier entre elles pour créer des animations plus complexes, tout en respectant l'objectif de 60 FPS.

Modifiez la taille d'un élément avec  scale

Pour utiliser la propriété  transform  sur un élément, nous devons lui fournir la fonction (ou les fonctions, comme on va le voir) qui déclenche les transformations souhaitées. Par exemple, pour faire passer un objet à 200 % de sa taille de départ, on utilise la fonction  scale()  paramétrée à 2 :

.btn {
    &:hover + .box {
        transform: scale(2);
    }
}

.box {
    transition: transform 330ms ease-in-out;
}

Plutôt que d’exprimer  scale()  en pourcentages, on indique des nombres, 0 pour 0 %, et 1 égal à 100 %.   scale(2)  fait donc grossir notre élément à 200 % de sa taille :

Une animation d'un carré qui grossit et rétrécit sans fluidité

Donner une seule valeur à la fonction  scale()  modifie la taille de l’élément de manière uniforme, aussi bien en hauteur qu'en largeur. Mais on peut également lui préciser deux valeurs, une pour modifier la largeur (X), et une autre pour modifier la hauteur (Y).

Par exemple, ici, nous souhaitons garder un volume constant. Il faut donc affiner la largeur de la boîte en même temps que nous allongeons sa longueur. Passons l’échelle de X à 300 %, et Y à 50 % :

.btn {
    &:hover + .box {
        transform: scale(3, 0.5);
    }
}
.box {
    transition: transform 330ms ease-in-out;
}

Maintenant, notre boîte s’étire horizontalement :

Une animation d'un carré qui devient un rectangle allongé

Et si je veux modifier ma boîte dans une seule direction ? 🧐

On pourrait faire quelque chose comme ça :

.btn {
    &:hover + .box {
        transform: scale(2, 1);
    }  
}
.box {
   transition: transform 330ms ease-in-out;
}

Ça fonctionne : l’axe X est à 200 % et l’axe Y à 100 %… Mais il existe une méthode plus propre et plus explicite.

Quand on veut modifier l’échelle dans une seule direction, on peut utiliser les fonctions  scaleX()  et   scaleY().   scaleX()  permet de modifier un objet horizontalement, et  scaleY()  verticalement.

Alors, pour passer l’échelle de notre bouton à 200 % horizontalement, nous pouvons utiliser  scaleX(2)  :

.btn {
    &:hover + .box {
        transform: scaleX(2);
    }
}
.box {
    transition: transform 330ms ease-in-out;
}

Une animation d'un carré qui devient un rectangle allongé

Félicitations ! Vous maîtrisez maintenant une des fonctions les plus utiles de transform 🎉 !

Découvrons maintenant la suite !

Modifiez la position d'un élément

La fonction  translate  est le moyen idéal pour modifier la position d'un élément dans une animation web.  translate()  prend deux valeurs en paramètres. La première indique la distance à laquelle on veut se déplacer sur l’axe X, et la seconde la distance sur l’axe Y.  Elle accepte différentes unités, comme  les px, les vh ou les em. Nous pouvons donc déplacer notre boîte de 150 px vers la droite et 7 vh vers le haut, comme ça :

.btn {
    &:hover + .box {
        transform: translate(150px, -7vh);
    }
}
.box {
    transition: transform 330ms ease-in-out;
}

Ce qui nous donne :

Une animation d'un carré qui se déplace en diagonale

Vous pouvez également utiliser des pourcentages. Pour certaines propriétés CSS, les pourcentages sont calculés par rapport à leur élément parent. Par exemple, width: 50%  signifie la moitié de la largeur du parent :

Une illustration de width: 50%

Mais quand on utilise des pourcentages avec   translate(), ces pourcentages sont liés à l’élément lui-même. Disons que notre élément fait 100 px de large :

.btn {
    &:hover + .box {
        transform: translate(100%, 0);
    }
}
.box {
    width: 100px;
    height: 100px;
    transition: transform 330ms ease-in-out;
}

Si on se déplace de 100 % sur l’axe X, on se déplace de 100 px vers la droite :

Une animation d'un carré qui se déplace à l'horizontale

Comme nous l'avons vu avec   scale(), il est possible de déplacer des éléments sur l’axe X et Y séparément, grâce aux fonctions  translateX()  et  translateY()

Ajoutons un peu de texte que nous allons faire apparaître dans la boîte :

<div class="container">
    <button class="btn">Transform!</button>
    <div class="box">
        Boop!
    </div>
</div>

La structure convient, mais pour animer le texte séparément de son élément parent, nous devons l’envelopper dans un conteneur. Plaçons-le donc au sein d’un  <span>  :

<div class="container">
    <button class="btn">Transform!</button>
    <div class="box">
        <span>Boop!</span>
    </div>
</div>

<span>  donne à la propriété  transform un élément auquel s’accrocher pour le manipuler. Réglons maintenant notre propriété  transform  pour qu’elle utilise  translateY(). Cela permet d'avoir notre texte hors de la boîte au début de l'animation, puis de le faire défiler dedans : 

.btn {
    &:hover + .box {
        transform: scale(1);
        span {
            transform: translateY(0);
        }
    }
}
.box {
    transform: scale(0.1);
    transition: transform 330ms ease-in-out;
    overflow: hidden;
    span {
        display: inline-block;
        transform: translateY(250%);
        transition: transform 280ms ease-out 50ms;
    }
}

Vous avez remarqué le changement de la valeur de display en   inline-block ? En effet, la valeur de display par défaut de  <span>  est inline. Or,  transform  ne peut pas manipuler d’éléments inline. Nous devons donc modifier le mode d’affichage en   block  ou   inline-block  avant d’obtenir des résultats.

Vous avez peut-être aussi remarqué que le texte n'apparaît pas tant qu'il n'est pas dans la boîte : c'est la propriété  overflow: hidden;  qui nous permet cela.

Nous avons aussi ajouté à notre transition  span  un petit délai et raccourci sa durée, pour qu’elle agisse un peu comme une animation secondaire (principe d’animation numéro 8 ! 🤘).

Une animation d'un petit carré qui grossit

Faites pivoter vos éléments avec rotate()

Maintenant que vous maîtrisez translate et scale, voyons la dernière fonction du trio gagnant :  rotate()  !

On peut paramétrer  rotate()  en plusieurs unités. Nous verrons ici les plus simples à utiliser : les degrés exprimés en "deg" et les turns. Un turn correspond à 360 degrés, ce qui est plutôt intuitif. Il s'agit donc de tours sur soi-même.

Faisons un test ! Prenons deux boîtes, chacune avec ses propres unités de rotation :

<div class="container">
    <button class="btn">Transform!</button>
    <div class="boxes">
        <div class="boxes__base boxes--rotDegrees">rotate(360deg)</div>
        <div class="boxes__base boxes--rotTurns">rotate(1turn)</div>
    </div>
</div>

Les deux boîtes sont placées dans la div  .boxes. Rappelez-vous que pour animer les propriétés d’un objet en CSS, elles doivent se trouver à côté de l’élément suivant dans la hiérarchie. Nous pouvons donc maintenant sélectionner les boîtes individuellement et les animer séparément :

.btn {
    &:hover + .boxes {
        & > .boxes--rotDegrees {
            transform: rotate(0deg);
        }
        & > .boxes--rotTurns {
             transform: rotate(0turn);
        }
    }
}

.boxes {
   &--rotDegrees {
        transform: rotate(-360deg);
        transition: transform 500ms ease-in-out;
    }

    &--rotTurns {
        background: pink;
        transform: rotate(-1turn);
        transition: transform 500ms ease-in-out;
    }
}

Chaque boîte démarre en position de rotation négative de 360 deg/1 turn. Au survol du bouton, cela déclenche la transition. On les fait alors tourner vers la position 0 deg/0 turn sur une demi-seconde, en utilisant la fonction de temporisation ease-in-out.

L'animation de deux carrés qui font une rotation

Le résultat final est exactement le même pour les deux boîtes. À vous de choisir entre degrés et turns selon vos préférences. Pour ma part, j'ai tendance à préférer turn lorsque mon élément fait au moins un tour sur lui-même, et deg lorsqu'il s'agit de valeurs inférieures à un tour.

Combinez les fonctions scale, position et rotate !

Reprenons la boîte que nous avions utilisée en combinant scale et translate. Nous pouvons maintenant complexifier le tout en ajoutant une rotation au texte.

.btn {
    &:hover + .box {
        transform: scale(1);
        transform: rotate(0deg); 
    span {
            transform: translateY(0);
        }
    }
}
.box {
   overflow: hidden;
   transform: scale(.1);
   transform: rotate(-90deg);
   transition: transform 330ms ease-in-out;
  span {
      transform: translateY(250%);
      transition: transform 280ms ease-out 50ms;
      display: block;
  } 
}

Maintenant, pendant que la boîte s’agrandit et que le texte apparaît, elle devrait également tourner d’un quart de tour, de -90 deg à 0 deg :

L'animation d'un carré qui pivote mais dont l'écriture disparaît

Zuuuuuuut ! 😭 On a tout cassé !

La boîte  pivote, mais notre animation scale a disparu. Comme si la transformation rotate() écrasait la transformation  scale()...

Mettons un commentaire sur notre  rotate()  pour vérifier que nous n’avons pas causé un problème dans le  scale()  :

.btn {
    &:hover + .box {
        transform: scale(1);
        // transform: rotate(0deg);
        span {
            transform: translateY(0);
        }
    }
}
.box {
    overflow: hidden;
    transform: scale(.1);
    // transform: rotate(-90deg);
    transition: transform 330ms ease-in-out;
    span {
        transform: translateY(250%);
        transition: transform 280ms ease-out 50ms;
        display: block;
    }
}

L'animation d'un petit carré qui grossit

Bon. Pourtant,  scale()  semble toujours fonctionner.

Le problème vient du fait qu’on ne peut assigner qu’une seule propriété  transform  à un élément. Je vous conseille de le noter dans un coin de votre tête si vous voulez éviter de vous arracher les cheveux 🙃

Alors, comment faire pour avoir plusieurs transformations dans une seule propriété  transform  ?

Pour cela, faites une liste de toutes les fonctions que vous voulez utiliser dans la propriété  transform.

Pour créer un effet qui combine rotation et changement d'échelle, nous devons indiquer la fonction  rotate()  à la suite de  scale()  dans la propriété  transform :

.btn {
    &:hover + .box {
        transform: scale(1) rotate(0deg);
        span {
            transform: translateY(0);
        }
    }
}
.box {
    overflow: hidden;
    transform: scale(.1) rotate(-90deg);
    transition: transform 330ms ease-in-out;
    span {
        transform: translateY(250%);
        transition: transform 280ms ease-out 50ms;
        display: block;
    }
}

Ce qui donne :

L'animation d'un carré qui grossit avec du texte à l'intérieur

Yaaaay ! On a réussi ! Vous avez le droit à une petite danse de la victoire 🕺

Ici, l'ordre selon lequel vous effectuez la rotation et le changement d’échelle ne va pas poser de problème. En effet, les deux n’ont pas d’effet l’un sur l’autre. Une rotation de 90 degrés suivie d’un agrandissement de 200 % aura le même effet qu’un agrandissement de 200 % suivi d’une rotation de 90 degrés.

Pour scale  et translate, en revanche, c’est très différent. Si on déplace un élément de 200 % avant de l’agrandir à 200 %, cela aura un résultat très différent par rapport au fait de l’agrandir avant de le déplacer : 

.btn {
    &:active + .box {
        & > .box__base--tranxScale {
        transform: translateX(200%) scale(2);
    }
    & > .box__base--scaleTranx {
        transform: scale(2) translateX(200%);
        }
    }
}
.box {
    &__base {
        &--tranxScale {
            background-color: #15dea5;
            transition: transform 330ms ease-in-out;
        }
        &--scaleTranx {
            background-color: pink;
            transition: transform 330ms ease-in-out;
        }
    }
}

On applique  .box__base-tranxScale  à la première boîte : elle va commencer par appliquer la transformation  scale(),  suivie de  translateX().

La deuxième boîte fonctionne avec  .box__base--scaleTranx()  et appliquera la transformation  translateX(), suivie de   scale()  :

L'animation de deux carrés qui se déplacent vers la droite et grossissent

La boîte numéro 2 va bien plus loin que la première. Plus exactement deux fois plus loin. Pourquoi ? Parce que le navigateur exécute les fonctions transform dans l’ordre, et il utilise le layout de départ comme point d’origine pour les transformations.

En décomposant l’ordre des opérations de ces transformations, on voit bien la première boîte passer à 200 % d’échelle puis se déplacer sur la droite de 200 % de la taille originelle de la boîte :

L'animation d'un carré qui grossit et se déplace vers la droite

La boîte numéro 2, quant à elle, se déplace de la même distance de 200 %, mais au lieu de s’agrandir depuis le centre de sa nouvelle position, elle s’agrandit vers l’extérieur en partant du centre d'origine avant son déplacement :

L'animation d'un carré qui se déplace vers la droite et grossit

La boîte 2 s’est déplacée vers la droite de 200 %, puis la translation a été, dans les faits, doublée par l’échelle, la faisant de fait se déplacer de 400 % vers la droite 🤨

Penchez du bon côté de la force

Position, scale, et rotation. Voilà un arsenal déjà respectable.

Mais vous avez sûrement déjà scrollé vers le bas de la page : vous savez bien que nous n'avons pas fini ! Voyons maintenant la fonction  skew()  ! 

Dans le même esprit que position et scale, vous pouvez désormais incliner des objets horizontalement ou verticalement. Pour cela,  skew()  penche les bords horizontaux ou verticaux, ou même les deux, en utilisant les fonctions   skewX(),   skewY(), et  skew()  :

.box {
    &--skewX {
        transform: skewX(45deg);
    }
    &--skewY {
        transform: skewY(45deg);
    }
    &--skew {
        transform: skew(45deg, 45deg);
    }
}

Les fonctions skewX(), skewY() et skew()

Passez dans une nouvelle dimension

C’est à peu près tout pour les capacités de transform… en 2D.

Eh oui ! Vous n’auriez pas oublié une dimension, par hasard ? 😏

Les fonctions pour les transformations en 3D sont proches des versions 2D, à ceci près qu'elles ont également la capacité de transformer sur l’axe Z. Faisons un rapide tour d'horizon des fonctions 3D disponibles avec  transform  :

Une animation des fonctions 3D disponibles avec transform

Si les fonctions 3D ressemblent beaucoup aux fonctions 2D, vous avez peut-être remarqué une nouvelle fonction :  perspective().

La valeur qu’on donne à  perspective()  indique au navigateur à quelle "distance" se trouve le spectateur. Comme dans le monde réel, plus un objet est proche, plus le mouvement aura l’air important, alors qu’à l’inverse, un objet distant semblera plus statique.

.box {
    &--perspective75px {
        transform: perspective(75px) rotateX(45deg);
    }
    &--perspective150px {
        transform: perspective(150px) rotateX(45deg);
    }
    &--perspective300px {
        transform: perspective(300px) rotateX(45deg);
    }
}

Avec une perspective de 75 px, on se retrouve bien plus proche de la boîte qu’à 150 ou 300 px. La rotation 3D semble donc bien plus marquée que les transformations dont la perspective est plus grande.

Des animations perspectives avec différents pixels

On peut utiliser la perspective et les transformations 3D pour ajouter de la profondeur et des effets visuels à nos animations.

Vous voyez bien que plus le cours avance, plus nous repoussons les limites de ce qu'il est possible de faire en animations CSS ! Bientôt, votre créativité n'aura plus de limite. 🧙‍♂️

En résumé 

  • la propriété  transform  nous permet de manipuler et animer nos sites de presque toutes les manières, et comme tout se passe pendant l’étape composition, les animations sont bien fluides sur tous les supports ;

  • on peut déplacer des éléments avec les fonctions translate :   translate(),  translateX(),  translateY()  et  translate3d()  ;

  • on peut agrandir avec les fonctions scale :  scale(),   scaleX(),  scaleY()  et  scale3d()  ;

  • et on peut les faire pivoter grâce aux fonctions rotate :  rotate(),  rotateX(),  rotateY() et  rotateZ()  ;

  • si on ajoute une deuxième propriété  transform, elle annule la première. On ne peut donc définir qu’une seule propriété  transform  dans un même sélecteur ;

  • pour effectuer plusieurs transformations, on peut les lister dans une même propriété transform comme 

    transform:translateX(200%) scale(2)

    ;

  • une propriété avec plusieurs fonctions exécute les fonctions dans l’ordre, de droite à gauche ;

  • les fonctions de transformations en 3D comme translate3d(),  rotateZ()  et  scale3d()  ont également besoin de la fonction perspective pour indiquer au navigateur la distance à laquelle l'utilisateur se trouve : plus la distance est grande, moins l'animation sera marquée.

Dans le chapitre suivant, nous verrons comment effectuer des animations un peu plus spécifiques, telles qu'un mouvement de balancier. Rendez-vous au chapitre suivant !

Example of certificate of achievement
Example of certificate of achievement