TUTO : Comment créer des animations comme Apple via une vidéo

Découvrez comment mettre en place facilement des animations sur vos landings page de la même manière qu’Apple. Tout cela en moins de 30 minutes et avec seulement une librairie JavaScript: scrollMagic.

TUTO : Comment créer des animations comme Apple via une vidéo

Que l’on aime les produits d’Apple ou non, tout le monde s’accorde à dire qu’ils proposent tout de même de très belles pages produits. Que ce soit les visuels en très hautes qualités ou bien les animations au scroll qui nous permettent de se sentir acteur de la page puisque l’on peut dévoiler le produit comme on le souhaite, ces pages sont toujours des réussites visuellement parlant.

Voyons aujourd’hui comment mettre en place des animations au scroll sur une page web à la manière d’Apple avec une vidéo.

Débuter le projet

Avant toute chose on va commencer par débuter notre projet. Pour cela on va récupérer une vidéo que l’on veut utiliser. Pour ma part j’ai récupéré une vidéo sur le site d’Apple directement :

<video class="video" src="https://www.apple.com/105/media/us/macbook-pro-13/2020/f2b14406-42ad-405e-bfa0-71b52a0bfd67/anim/chip/large.mp4"></video>

On va alors créer une page classique en HTML avec une première section qui contient notre vidéo et une seconde section que l’on va afficher sous notre vidéo et après notre scroll.

<!doctype html>
<html lang="fr">
<head>
	<!-- Required meta tags -->
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">

	<link rel="stylesheet" href="assets/css/style.css">
	<title>Macbook Air - Apple</title>
</head>
<body>

<section class="m1Animation">
	<h1>Macbook Air</h1>
	<video class="video" src="https://www.apple.com/105/media/us/macbook-pro-13/2020/f2b14406-42ad-405e-bfa0-71b52a0bfd67/anim/chip/large.mp4"></video>
</section>
<section class="revolution">

</section>
</body>
</html>


Je complète ma seconde section avec une card contenant un petit texte marketing et une belle image. Voyons comment embellir tout cela avec un peu de CSS juste après.

<section class="revolution">
    <div class="container">
        <div class="row">
            <div class="col-12">
                <div class="card">
                    <div class="row">
                        <div class="col-6">
                            <h1>Revolution is here</h1>
                            <div class="subtitle">Power never reached such level</div>
                            <p class="py-5">The M1 chip makes MacBook Pro outrageously fast and powerful. Its 8 core CPU rips through complex workflows and heavy workloads, with up to 2.8x faster processing performance than the previous generation2 - all with unbelievable energy efficiency.</p>
                            <button class="btn-outline-secondary">Order now</button>
                        </div>
                        <div class="col-6">
                            <img src="http://apple.com/v/macbook-pro-13/g/images/overview/processor__t4s51e0n7giy_large_2x.png" class="overview-processor-img" width="100%" height="100%" alt="">
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</section>

Un peu de CSS

On va ajouter à ce HTML un peu de CSS afin notamment de centrer tout le contenu et obtenir quelque chose qui sera plus sympa visuellement.
On commence par supprimer tous les margin/padding de base et définir les quelques class qui seront utiles sur l’ensemble du projet (on notera une légère inspiration du fonctionnement de BootStrap) :

*{
    margin:0;
    padding:0;
}
body{
    background: black;
}
.container{
    max-width:1140px;
    margin-left:auto;
    margin-right:auto;
}
.row{
    display:flex;
    align-items: center;
    justify-content: space-between;
}
.col-6{
    width:49.99%;
}
.col-12{
    width:100%;
}
.py-5{
    padding:3rem 0;
}

Après cela je m’occupe de ma section m1-animation afin de passer un arrière plan noir, centrer la vidéo et écrire le texte en blanc.

.m1Animation{
    background: #000;
    display: flex;
    align-content: center;
    justify-content: center;
    width: 100%;
    color:white;
    padding:5rem 0;
    height:100vh;
}

Passons maintenant au titre (H1) que nous plaçons en absolute au dessus de la vidéo et à 400px du haut afin de le centrer a peu près. Je ne cherche pas à faire quelque chose de parfait ici, juste avoir quelque chose qui rend à peu près bien sur mon écran.

.m1Animation h1{
    text-align: center;
    position: absolute;
    top:400px;
    left: 50%;
    transform: translateX(-50%);
    font-size:90px;
}

Enfin je m’occupe de la vidéo ainsi que de notre deuxième section où l’on a ajouté notre card et notre notre image. J’ajoute notamment un dégradé en arrière plan de ma card et un peu de style pour les autres éléments.

.m1Animation video{
    width:100%;
    height: auto;
}
.revolution{
    padding: 10rem 0;
    background-color: black;
}
.revolution .card{
    background: linear-gradient(to right top, #071931 0%, #33274f 50%, #661e43 100%);
    border-radius: 30px;
    padding:3rem 0 3rem 3rem;
    color:white;
}
.revolution .card h1{
    font-size:60px;
    font-weight: 600;
}
.revolution .card .subtitle{
    color: #8679cb;
    font-size:30px;
    font-weight: 200;
}
.revolution .card .btn-outline-secondary{
    background-color:transparent;
    border: 2px solid white;
    border-radius: 40px;
    padding: 10px 30px;
    color: white;
}
.revolution .card .btn-outline-secondary:hover{
    background-color: white;
    color: black;
}

Le JavaScript

Importation des librairies

Vous vous en doutez probablement, pour créer nos animations nous allons devoir utiliser du JavaScript pour pouvoir « tracker » la position du scroll et donc de l’utilisateur sur la page.

Pour cela nous allons utiliser une librairie en JS nommé Scroll Magic.
Elle va nous permettre de détecter la position de l’utilisateur mais pas de réaliser les animations que nous souhaitons. Pour cela nous allons la combiner à une autre librairie : GSAP.

Je vous laisse donc intégrer à votre HTML les différents scripts JS :

<script src="https://pagecdn.io/lib/scrollmagic/2.0.7/ScrollMagic.min.js" crossorigin="anonymous"></script>
<script src="https://pagecdn.io/lib/scrollmagic/2.0.7/plugins/animation.gsap.min.js" crossorigin="anonymous"  ></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js" crossorigin="anonymous"></script>
<script src="https://pagecdn.io/lib/scrollmagic/2.0.7/plugins/debug.addIndicators.min.js" crossorigin="anonymous"  ></script>

La première ligne ici nous permet d’importer la librairie Scroll Magic, la seconde nous permet de récupérer la partie animation GSAP au sein de la librairie Scroll Magic. La 3ème (TweenMax) va nous permettre d’ajouter un fondu sur le texte afin de le faire disparaitre progressivement et enfin, la dernière ligne nous permettra de débuguer facilement grâce à des indicateurs visuels

Notre JS

Nos librairies sont désormais importées au sein de notre de notre projet, il faut désormais les utiliser et les appliquer correctement à notre projet !

Pour cela rien de bien compliqué, créez un fichier app.js et ajoutez-le dans votre HTML comme ceci :

<script src="assets/js/app.js"></script>

Avant toute chose, commençons par définir nos variables nous permettant de cibler nos différents éléments :
Je créé donc 6 variables me permettant de cibler les différents éléments importants de ma page que je souhaite animer ou que je vais utiliser comme triggers (déclencheurs) pour démarrer/arrêter mes animations.

const m1Section = document.querySelector('.m1Animation');
const video = m1Section.querySelector('video');
const text = m1Section.querySelector('h1');

const section = document.querySelector('.revolution');
const end = section.querySelector('h1');
const card = section.querySelector('.card');

Nous allons pouvoir maintenant intégrer nos librairies JS. Commençons par créer un controller ScrollMagic. Il va nous permettre de déclencher nos différentes animations.

const controller = new ScrollMagic.Controller();

À la suite de cela créons une scène Scroll Magic afin de définir une première animation et son comportement :

    const scene = new ScrollMagic.Scene({
    duration: 6000,
    triggerElement: m1Section,
    triggerHook: 0,
})
.setPin(m1Section)
.addIndicators()
.addTo(controller);

Regardons rapidement ces différentes lignes et essayons de les comprendre :
La première nous permet de définir une constante qui sera notre scène à laquelle on va passer plusieurs paramètres. Le premier est la durée de la scène, ici il correspond au temps de ma vidéo en millisecondes, c’est à dire jusqu’à quand mon animation va se réaliser. Le second paramètre est notre élément de trigger, c’est sur celui-ci que nous allons exécuter notre animation. Enfin, la dernière ligne correspond au « point d’accroche » a partir duquel nous allons déclencher l’animation. En l’occurence 0 signifie le haut de notre page, c’est à dire que dès le début du scroll l’animation va se lancer.

A la suite de cela on appelle 3 fonctions, setPin, addIndicators et addTo. La première permet de définir que tout le temps de l’animation nous allons positionner l’élément en paramètre (ici notre section) en position fixe. Cela va permettre d’avoir la vidéo qui s’anime au scroll mais de bloquer le scroll de la page et de conserver notre section en visuel. Sans ça, l’animation va se dérouler mais elle ne sera pas visible car elle sortira de l’écran.
La seconde fonction ajoutée, addIndicators, va nous permettre d’afficher des éléments pour débuguer notre code afin de voir les triggers etc…
Enfin, la fonction addTo nous permet d’ajouter cette scène à notre Controller afin qu’il l’exécute.

Une fois que nous avons réalisé cela il va falloir récupérer la position du scroll de l’utilisateur et définir cette position comme notre temps dans la vidéo. Pour cela, on va commencer par définir 3 variables qui nous seront utiles par la suite.

let accelamount = 0.1;
let scrollpos = 0;
let delay = 0;

La variable accelamount va nous permettre d’éviter de s’arrêter subitement quand l’utilisateur s’arrête de scroller. Cela va permettre d’avoir un effet un peu plus smooth.
La variable scrollpos définie tout simplement la position du scroll de l’utilisateur. On l’instancie à 0 mais elle va être modifié à chaque mouvement de l’utilisateur.
Enfin, la variable delay va également permettre d’avoir un mouvement smooth. Cette cette variable que l’on va passer à la vidéo en faisant un calcul par rapport aux variables scrollpost & accelamount.

Après cela nous pouvons mettre à jour la variable scrollpos lorsque l’utilisateur scroll. Pour cela nous allons utiliser un évènement JS :

    scene.on('update', e=> {
    scrollpos = e.scrollPos / 1000;
})

Lorsque la scène est mise à jour alors on récupère la position depuis l’évènement de la librairie scrollMagic que l’on divise par 1000. Pourquoi 1000 ? Tout simplement parce que la « duration » que nous avons renseignée plus tôt était en millisecondes et que notre vidéo est en secondes.

Enfin, on termine par mettre à jour notre affichage et changer le « currentTime » de notre vidéo afin que l’on scroll dans la vidéo :

setInterval(() =>{
    delay += (scrollpos - delay) * accelamount;
    video.currentTime = delay ;
}, 33.3)

Notre animation est donc prête ! Notre vidéo va s’animer au fur et à mesure de notre scroll et donner un côté très immersif à notre page

Allons plus loin

Une fois l’animation réalisée on peut aller plus loin et faire apparaître par exemple le texte principal via une animation CSS ou encore faire apparaitre la card de notre deuxième partie via une animation.
Voyons ensemble comment ajouter cela !

Animer mon titre en CSS

Pour faire une apparition de mon titre en CSS il me suffit simplement de lui fixer une opacité à 0 puis de la monter progressivement à 1. Cela va permettre d’arriver sur une page totalement noire et d’avoir un texte qui apparait subitement après X secondes au milieu de la page.

Pour faire ça, rien de bien compliqué, il va juste falloir définir l’opacité de base de notre élément à 0 et à l’aide des @keyframes en CSS, redéfinir l’opacité à 1 après un temps donné. Cela nous donne donc ce code ci :

.m1Animation h1{
    animation: display-smooth 3s;
    opacity: 100%;
    z-index: 1;
}
@keyframes display-smooth {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 100%;
    }
}

Après avoir testé, j’en profite pour ajouter la même chose sur ma vidéo afin qu’elle apparaisse aussi lentement que mon texte

.video{
    animation: display-smooth 3s;
    opacity: 100%;
    z-index:0;
}

Faire disparaitre mon titre au scroll

Une fois que mon texte apparaît et ma vidéo apparaissent lentement je voudrais que mon titre disparaissent au scroll pour laisser la place à la vidéo au fur et à mesure.

Pour cela on va repasser en JS et ajouter une nouvelle scène.

const textAnim = TweenMax.fromTo(text, 5, {opacity:1}, {opacity: 0})
let scene2 = new ScrollMagic.Scene({
    duration: 1800,
    triggerElement: m1Section,
    triggerHook: 0
})
.setTween(textAnim)
.addTo(controller);

On créé donc une nouvelle variable que l’on défini grâce à notre librairie TweenMax. Cela va nous permettre de définir une animation simple : from A to B.
Ici on va donc définir l’animation sur l’objet text que j’ai défini auparavant, avec une opacité allant de 1 à 0. Le 5 représente globalement le taux auquel l’animation va se réaliser. Par exemple si on renseigne 0 cela va passer d’un coup sec de 1 à 0.

Après cela on défini une nouvelle scène à laquelle on assigne une durée de 1.8 secondes, toujours le même élément déclencheur, m1Section et enfin on déclenche l’animation dès le départ avec un triggerHook à 0.
On lui passe après cela 2 fonction, setTween ou l’on ajoute notre animation définie auparavant et on l’ajoute comme tout à l’heure à notre controller.
Et la magie ! Ça fonctionne parfaitement. Le texte disparait après 1,8 secondes de scroll environ et le fait de manière discrète.

Faire apparaître ma section au scroll

Désormais si l’on souhaite terminer notre page et faire apparaitre notre seconde section « revolution » au scroll, il suffit de refaire sensiblement la même chose.
Je commence par définir mes variables pour pouvoir cibler mes éléments simplement :

    const section = document.querySelector('.revolution');
const end = section.querySelector('h1');
const card = section.querySelector('.card');

Puis je définis une nouvelle scène afin de créer l’animation sur ma card pour qu’elle apparaisse en « fondu ». On retrouve globalement les mêmes paramètres : triggerElement, triggerHook, duration, et on ajoute le paramètre offset qui permet de déplacer le trigger au centre de notre card.
Enfin on définit la classe que l’on va activer/désactiver via le setClassToggle(card, « visible »).

    let scene3 = new ScrollMagic.Scene({
    triggerElement: end,
    triggerHook: 0.9, 
    duration: "80%", 
    offset: 50 // move trigger to center of element
})
    .setClassToggle(card, "visible") // add class to reveal
    .addTo(controller);

Si vous êtes arrivé ici et que vous avez tout lu vous avez même le droit et la chance d’avoir accès à tout ce code condensé dans un repository GitHub ! Voir sur GitHub