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é.
Exemple
#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')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
#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é parrequestAnimationFrame(), transmis àcancelAnimationFrame().
Plus d’exemples
#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)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.
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)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.
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
transitionou@keyframes. Le navigateur les anime plus efficacement et sans code JavaScript.
Entrées associées
#- setTimeout()Exécute une fonction une seule fois, après le nombre de millisecondes indiqué.
- setInterval()Appelle une fonction de façon répétée, à l’intervalle donné, jusqu’à l’arrêt par clearInterval().
- HTMLElement.styleUn objet pour les styles écrits directement sur l’élément (inline), pour lire et modifier des propriétés CSS individuelles.
- ResizeObserverAppelle une fonction chaque fois que la taille d’un élément observé change, quelle qu’en soit la cause.
- Element.getBoundingClientRect()Renvoie la taille d’un élément et sa position par rapport à la zone visible de la fenêtre, sous la forme d’un objet DOMRect.
Vous voyez une erreur ou il manque un exemple ? Écrivez-nous.