requestAnimationFrame()

Planifie l’appel d’une fonction juste avant le prochain rafraîchissement de l’écran. Sert à créer des animations fluides pilotées par JavaScript.

Renvoie
Un nombre, l’identifiant de l’appel planifié.
Sur cette page

Exemple

#
JavaScript
const bar = document.querySelector('#bar')
const duration = 600
let start

function step(timestamp) {
  if (start === undefined) start = timestamp
  const progress = Math.min((timestamp - start) / duration, 1)
  bar.style.width = `${progress * 100}%`

  if (progress < 1) {
    requestAnimationFrame(step)
  } else {
    console.log('Barre remplie :', bar.style.width)
  }
}

requestAnimationFrame(step)
console.log('Animation planifiée')
Console
Animation planifiée
Barre remplie : 100%

La progression est calculée à partir du temps écoulé, donc la barre se remplit en 0,6 s quel que soit le nombre d’images par seconde. Cliquez sur « Relancer » pour revoir l’animation.

Définition et utilisation

#

La fonction requestAnimationFrame() demande au navigateur d’appeler la fonction donnée avant de dessiner l’image suivante. Cela se produit généralement 60 fois par seconde, et plus souvent sur les écrans à taux de rafraîchissement plus élevé. Les changements d’apparence arrivent alors à l’écran exactement au moment où le navigateur dessine de toute façon la page, donc l’animation est plus fluide qu’avec setInterval().

La fonction de rappel ne s’exécute qu’une seule fois. Pour construire une animation, planifiez la suivante à la fin de chaque image, en rappelant requestAnimationFrame(). La fonction reçoit un horodatage en millisecondes (sur la même échelle que performance.now()), qui permet de calculer la progression à partir du temps écoulé plutôt que du nombre d’images. L’animation dure alors le même temps sur chaque écran.

L’appel renvoie un identifiant qui, transmis à cancelAnimationFrame(), annule l’image planifiée. Dans les onglets qui tournent en arrière-plan et dans les cadres invisibles, le navigateur suspend les appels, ce qui économise la batterie. Les transitions et animations simples sont mieux décrites en CSS (transition, @keyframes), et requestAnimationFrame() est à réserver aux mouvements qui dépendent de calculs, par exemple dans les jeux et les graphiques.

Syntaxe

#
Syntaxe
requestAnimationFrame(callback)

cancelAnimationFrame(requestId)

Paramètres

#
  • callback

    function (timestamp)

    La fonction appelée avant l’image suivante. Elle reçoit un horodatage en millisecondes.
  • requestId

    nombre

    L’identifiant renvoyé par requestAnimationFrame(), transmis à cancelAnimationFrame().

Plus d’exemples

#
Compteur de points pas à pas
JavaScript
const points = document.querySelector('#points')
const target = 150
let value = 0

function tick() {
  value = Math.min(value + 30, target)
  points.textContent = value
  console.log(value)
  if (value < target) requestAnimationFrame(tick)
}

requestAnimationFrame(tick)
Console
30
60
90
120
150

Chaque image augmente le compteur de 30, donc l’animation se termine après cinq images, soit environ 80 ms sur un écran à 60 Hz. Sur un écran à 120 Hz, le même code s’exécute deux fois plus vite, c’est pourquoi, dans les animations plus longues, le pas se calcule à partir du temps écoulé, comme dans le premier exemple.

Annuler une image planifiée
JavaScript
const tile = document.querySelector('#tile')

const moveId = requestAnimationFrame(() => {
  tile.style.transform = 'translateX(200px)'
  console.log('Tuile déplacée')
})

requestAnimationFrame(() => {
  console.log('Image prête, décalage :', tile.style.transform || 'aucun')
})

cancelAnimationFrame(moveId)
console.log('L’identifiant de l’image est', typeof moveId)
Console
L’identifiant de l’image est number
Image prête, décalage : aucun

La première fonction planifiée a été annulée avant l’image suivante, donc la tuile ne s’est pas déplacée. La seconde s’est exécutée normalement.

Au plus une mise à jour par image
JavaScript
const header = document.querySelector('header')
let scheduled = false

window.addEventListener('scroll', () => {
  if (scheduled) return
  scheduled = true

  requestAnimationFrame(() => {
    header.classList.toggle('with-shadow', window.scrollY > 0)
    scheduled = false
  })
})

L’événement scroll peut se déclencher plusieurs fois au cours d’une seule image. Le drapeau scheduled garantit que l’apparence de l’en-tête n’est mise à jour qu’une fois par image au maximum, juste avant le dessin.

Compatibilité des navigateurs

#

Largement disponible

Fonctionne dans tous les navigateurs modernes, y compris sur mobile. Vous pouvez l’utiliser sans crainte.

  • Chrome
  • Edge
  • Firefox
  • Safari

Bonnes pratiques

#
  • Calculez la progression de l’animation à partir du temps écoulé (timestamp), pas du nombre d’images. Un écran à 120 Hz a deux fois plus d’images qu’un écran à 60 Hz.
  • Chaque appel ne planifie qu’une seule image. Si l’animation doit continuer, rappelez requestAnimationFrame() à l’intérieur de la fonction.
  • Décrivez les transitions simples en CSS avec transition ou @keyframes. Le navigateur les anime plus efficacement et sans code JavaScript.

Entrées associées

#

Vous voyez une erreur ou il manque un exemple ? Écrivez-nous.