Que fait Apple Design ?
Réponse initiale
Lorsque cette compétence est invoquée pour la première fois sans question spécifique, répondez uniquement par :
Je suis prêt à vous aider à créer des interfaces fluides de style Apple sur le web, mes connaissances proviennent des conférences de design d'Apple à la WWDC, traduites pour le web.
Ne fournissez aucune autre information tant que l'utilisateur n'a pas posé de question.
Comment Apple construit des interfaces qui cessent de ressembler à un ordinateur et commencent à ressembler à une extension de vous-même. Ces connaissances proviennent des conférences de design d'Apple à la WWDC — principalement Designing Fluid Interfaces (WWDC 2018) — distillées et traduites pour la plateforme web (CSS, Pointer Events, requestAnimationFrame, bibliothèques de ressorts comme Motion/Framer Motion).
Le fil conducteur : une interface est vivante lorsque le mouvement commence à partir de la valeur actuelle à l'écran, hérite de la vélocité de l'utilisateur, projette le momentum vers l'avant, et peut être saisie et inversée à tout instant. Les ressorts sont l'outil qui rend tout cela naturel, car ils sont intrinsèquement interruptibles et conscients de la vélocité.
L'idée centrale
« Lorsque nous alignons l'interface sur notre façon de penser et de bouger, quelque chose de magique se produit — elle cesse de ressembler à un ordinateur et commence à ressembler à une extension transparente de nous-mêmes. »
Une interface est fluide quand elle se comporte comme le monde physique : les choses répondent instantanément, bougent continuellement, transportent le momentum, résistent aux limites, et peuvent être redirigées en plein mouvement. Tout ce qui suit est un moyen de s'en rapprocher.
Apple présente le design comme servant quatre besoins humains : la sécurité/prévisibilité, la compréhension, la réussite et la joie. Chaque règle ici sert l'un d'entre eux.
1. Réponse — éliminer la latence
Dès que la latence apparaît, la sensation de réactivité « chute de manière abrupte. » La réponse est le fondement sur lequel tout le reste est construit.
- Répondez au pointer-down, pas au relâchement. Mettez en surbrillance un bouton dès qu'il est pressé. Attendre le
click/la levée du doigt pour montrer un retour d'information donne une impression de mort. - Soyez vigilant à chaque latence. Auditez les debounces, les minuteries artificielles, les attentes de transition, et le délai de tap d'environ 300 ms. Tout ce qui se trouve sur le chemin d'entrée qui n'est pas essentiel est une régression.
- Le retour d'information doit être continu pendant l'interaction, pas seulement à la fin. Pour un glissement, un curseur ou un tiroir, mettez à jour l'UI 1:1 avec le pointeur tout au long du parcours — n'animez jamais uniquement lorsque le geste est terminé.
/* Le retour d'information vit sur la pression, et il est instantané */
.button:active {
transform: scale(0.97);
transition: transform 100ms ease-out;
}
2. Manipulation directe — suivi 1:1
« Le toucher et le contenu doivent bouger ensemble. »
Lorsque l'utilisateur fait glisser quelque chose, cela doit rester collé au doigt — et respecter le décalage par rapport à l'endroit où il l'a saisi. S'accrocher au centre de l'élément lors de la saisie brise immédiatement l'illusion.
- Utilisez Pointer Events avec
setPointerCapturepour que le suivi continue même lorsque le pointeur quitte les limites de l'élément. - Suivez un court historique de vélocité/position (les derniers événements
pointermove), pas seulement le point actuel — vous aurez besoin de la vélocité au moment du relâchement.
el.addEventListener('pointerdown', (e) => {
el.setPointerCapture(e.pointerId);
const grabOffset = e.clientY - el.getBoundingClientRect().top; // respecter l'endroit où ils ont saisi
// ...suivre la position + l'horodatage pour la vélocité
});
3. Interruptibilité — le principe le plus important
« La pensée et le geste se produisent en parallèle. »
Chaque animation doit être interruptible et redirigeable à tout moment. Un utilisateur doit pouvoir saisir un élément en mouvement en plein vol et l'inverser sans attendre la fin de l'animation. Une fenêtre modale en cours de fermeture que l'utilisateur saisit à nouveau doit suivre le doigt — pas finir de se fermer d'abord, puis se rouvrir.
- Ne verrouillez jamais l'entrée pendant une transition.
- Animez toujours à partir de la valeur de présentation (actuelle), jamais de la valeur cible. En cas d'interruption, lisez la transformation en direct à l'écran de l'élément et démarrez la nouvelle animation à partir de là. Commencer à partir de la valeur logique/cible provoque un saut visible.
- Évitez les transitions CSS et les
@keyframespour tout ce qui est piloté par un geste — ils ne peuvent pas être saisis et inversés en douceur en plein vol. Les ressorts animent à partir de la valeur actuelle par défaut, ce qui est exactement ce dont l'interruption a besoin. - Lorsqu'un geste s'inverse, mélangez la vélocité — ne la coupez pas brutalement. Remplacer une animation par une autre lors d'une inversion crée une discontinuité de vélocité, un « mur de briques. » Les bibliothèques de ressorts qui transportent la vélocité lors d'un re-ciblage l'évitent. (C'est ce que fait iOS nativement avec les animations additives ; sur le web, choisissez une bibliothèque de ressorts qui re-cible à partir de la vélocité actuelle.)
- Décomposez le mouvement 2D en ressorts X et Y indépendants. Un seul ressort sur une distance 2D se désynchronise lorsque X et Y ont des vélocités différentes.
4. Comportement plutôt qu'animation — utilisez des ressorts
« Pensez à l'animation comme à une conversation entre vous et l'objet, pas comme à quelque chose de prescrit par l'interface. »
Une animation pré-définie et de durée fixe ne peut pas répondre à de nouvelles entrées. Un ressort le peut — une nouvelle entrée change simplement la cible, et le mouvement reste continu. Utilisez des ressorts pour tout ce qu'un utilisateur peut toucher.
Apple a délibérément remplacé le triplet physique (masse/rigidité/amortissement) par deux paramètres plus adaptés aux concepteurs. Pensez en ces termes :
- Taux d'amortissement — contrôle le dépassement.
1.0= amortissement critique, pas de rebond, stabilisation lisse.< 1.0= dépasse et oscille. Plus bas = plus rebondissant. - Réponse — la rapidité avec laquelle la valeur atteint la cible, en secondes. Plus bas = plus rapide. Ce n'est pas la « durée » — un ressort n'a pas de durée fixe ; son temps de stabilisation émerge des paramètres.
Valeurs par défaut :
- Commencez la plupart des UI avec un amortissement
1.0(amortissement critique) — gracieux et non distrayant. - Ajoutez du rebond (amortissement ~
0.8) seulement lorsque le geste lui-même a transporté du momentum (un flick, un lancer, un relâchement de glissement). Un dépassement sur un menu qui vient d'apparaître semble faux ; un dépassement sur une carte que vous avez lancée semble juste.
Valeurs concrètes qu'Apple utilise :
| Interaction | Amortissement | Réponse |
|---|---|---|
| Déplacement / repositionnement (ex. PiP) | 1.0 | 0.4 |
| Rotation | 0.8 | 0.4 |
| Tiroir / feuille | 0.8 | 0.3 |
Correspondance web (Motion / Framer Motion) : l'API de ressort bounce + duration correspond étroitement à l'amortissement et à la réponse d'Apple. Un style de base sûr est d'utiliser des ressorts damping: 1.0 partout par défaut ; réservez le rebond pour les interactions physiques pilotées par le momentum.
import { animate } from 'motion';
// Par défaut avec amortissement critique (pas de dépassement)
animate(el, { y: 0 }, { type: 'spring', bounce: 0, duration: 0.4 });
// Interaction avec momentum — un peu de rebond, seulement parce qu'un flick l'a précédée
animate(el, { y: target }, { type: 'spring', bounce: 0.2, duration: 0.4 });
5. Transmission de vélocité — la jointure entre le glissement et l'animation
Lorsqu'un geste se termine, l'animation doit continuer à la vélocité exacte du doigt, de sorte qu'il n'y ait pas de jointure visible entre le glissement et l'animation. C'est le détail qui distingue le plus le « fluide » du « correct. »
Transmettez la vélocité de relâchement du pointeur comme vélocité initiale du ressort. Certaines API de ressort veulent une vélocité relative — normalisez-la par la distance restante jusqu'à la cible :
relativeVelocity = gestureVelocity / (targetValue − currentValue)
Exemple : élément à y=50, cible y=150 (100px à parcourir), doigt à 50px/s → vélocité initiale du ressort = 50 / 100 = 0.5. Framer Motion / Motion acceptent directement la vélocité absolue en px/s (option velocity), donc vous lui passez généralement la valeur brute.
6. Projection de momentum — animer vers l'endroit où le geste va
« Prenez une petite entrée et produisez une grande sortie. »
Ne vous accrochez pas à la limite la plus proche à partir du point de relâchement. Utilisez la vélocité pour projeter la position de repos — exactement comme la décélération du défilement — puis accrochez-vous à la cible la plus proche de ce point projeté. C'est ce qui fait qu'un flick semble lancer l'élément.
La fonction de projection exacte d'Apple (d'après le code exemple de Designing Fluid Interfaces) :
// decelerationRate ≈ 0.998 pour une sensation de défilement normale ; 0.99 pour plus de rapidité
function project(initialVelocity /* px/s */, decelerationRate = 0.998) {
return (initialVelocity / 1000) * decelerationRate / (1 - decelerationRate);
}
const projectedEndpoint = currentPosition + project(releaseVelocity);
const target = nearestSnapPoint(projectedEndpoint); // choisir la cible à partir de la projection
animateSpringTo(target, { velocity: releaseVelocity }); // puis transmettre la vélocité (§5)
Remarque : la formule v²/(2·decel) issue des manuels de physique n'est pas ce qu'Apple utilise — utilisez la forme de décroissance exponentielle ci-dessus. C'est le comportement standard dans les bons bottom-sheets et carrousels (Vaul, Embla).
7. Cohérence spatiale — chemins symétriques, origines ancrées
« Si quelque chose disparaît d'une certaine manière, on s'attend à ce qu'il émerge de là d'où il vient. »
- Entrez et sortez par le même chemin. Un panneau qui glisse depuis la droite doit disparaître vers la droite. Entrer par la droite / sortir par le bas donne une impression de déconnexion et de confusion.
- Ancrez les interactions à leur source. Un menu, une popover ou une feuille doit provenir de l'élément qui l'a déclenché — définissez
transform-originsur le déclencheur, afin que la relation spatiale entre le bouton et le contenu soit évidente. (C'est le même point de conscience de l'origine que les popovers qui s'étendent à partir de leur déclencheur, pas de leur centre.) - Miroitez l'assouplissement sur les transitions réversibles afin que le chemin de sortie corresponde au chemin de retour (utilisez des points de contrôle cubic-bézier inverses pour les deux directions).
8. Indice dans la direction du geste
Les humains prédisent un état final à partir d'une trajectoire. Le mouvement intermédiaire doit indiquer où les choses vont — les modules du Centre de contrôle « grandissent vers l'extérieur en direction de votre doigt. » Faites en sorte que les images intermédiaires pointent vers le résultat, pas seulement interpoler aveuglément vers lui.
9. Rubber-banding — limites souples
À une limite, résistez progressivement au lieu de vous arrêter brutalement. Un arrêt brutal se lit comme « gelé » ; une résistance continue se lit comme « réactif, mais il n'y a plus rien ici. » Appliquez un amortissement qui augmente d'autant plus que l'utilisateur dépasse la limite.
// Plus on dépasse la limite, moins l'élément suit — les objets réels ralentissent avant de s'arrêter
function rubberband(overshoot, dimension, constant = 0.55) {
return (overshoot * dimension * constant) / (dimension + constant * Math.abs(overshoot));
}
10. Détails de conception des gestes (la liste de contrôle de la « sensation »)
- Tap : mise en évidence au down du toucher (instantanée), validation au up du toucher. Ajoutez environ 10px d'hystérésis/rembourrage de la cible autour de la cible, et permettez d'annuler en glissant ailleurs et en revenant.
- Drag/swipe : exigez un petit seuil de mouvement (hystérésis, ~10px) avant de vous engager dans une direction, puis suivez 1:1.
- Détectez tous les gestes plausibles en parallèle dès le premier mouvement, puis annulez en toute confiance les perdants une fois l'intention claire. Évitez les reconnaisseurs qui ne rapportent qu'un état final (événements de type
swipeleft) — ils jettent le suivi continu dont vous avez besoin pour le retour d'information. - Minimisez les délais de désambiguïsation. La détection du double-tap retarde inévitablement les simples tap ; ne payez ce coût que là où le double-tap existe vraiment.
11. Fluidité au niveau de l'image
La fluidité concerne ce qu'il y a dans les images, pas seulement le taux d'images par seconde.
- Maintenez le changement de position par image en dessous du seuil de perception pour éviter le stroboscopie.
- Pour les mouvements très rapides, un flou de mouvement / étirement subtil encode la vitesse et se lit mieux qu'une traînée dure et nette.
requestAnimationFrameest l'horloge synchronisée avec l'affichage du web (Apple utiliseCADisplayLink). Animez uniquement les propriétés compatibles avec le compositeur —transformetopacity— et indiquez avecwill-changelà où le mouvement est imminent.
12. Matériaux et profondeur — la translucidité transmet la hiérarchie
Apple utilise des matériaux translucides comme une couche fonctionnelle flottante qui apporte de la structure sans voler l'attention. Sur le web, approximez avec backdrop-filter.
- Construisez les nav/bars d'outils/feuilles comme des couches translucides (
backdrop-filter: blur()+ un arrière-plan semi-transparent) avec le contenu qui défile en dessous — pas des barres opaques qui consomment une bande fixe. - Le poids du matériau encode la hiérarchie : les matériaux plus foncés/plus lourds séparent les régions structurelles (barres latérales) ; les matériaux plus légers attirent l'attention sur les éléments interactifs (boutons). N'empilez jamais une surface translucide claire sur une autre — la lisibilité s'effondre.
- Les surfaces plus grandes doivent être perçues comme plus épaisses : un flou plus fort + une ombre plus profonde que les petits éléments. Considérez une ombre contextuelle — plus lourde sur un contenu occupé/texte pour la séparation, plus légère sur des arrière-plans unis.
- Assombrissez pour concentrer, séparez pour maintenir le flux. Une tâche modale associe la surface à un écran d'assombrissement et repousse/abaisse l'arrière-plan. Un panneau parallèle non bloquant utilise la translucidité et le décalage sans écran d'assombrissement afin que le flux ne soit pas interrompu. Pour les feuilles empilées, assombrissez et repoussez progressivement chaque couche parente.
- La vibrancy maintient la lisibilité du texte sur des arrière-plans changeants. Sur des surfaces floues/translucides, n'utilisez pas de texte gris uni — utilisez un contraste plus élevé, un poids légèrement plus lourd et une légère augmentation de l'espacement des lettres. Mettez la couleur sur une couche solide, pas sur le premier plan translucide.
- Effets de bord de défilement, pas de séparateurs durs. Au lieu d'une bordure de 1px sous un en-tête collant, fondez un petit masque de flou/dégradé là où le contenu rencontre le chrome flottant — uniquement là où l'UI flottante chevauche réellement le contenu.
- Matérialisez, ne vous contentez pas de fondre. Pour les surfaces en verre/flou, animez le rayon de flou et l'échelle ensemble lors de l'entrée/sortie, de sorte que la surface soit perçue comme un matériau réel arrivant plutôt qu'un simple fondu d'opacité.
.toolbar {
background: rgba(255, 255, 255, 0.6);
backdrop-filter: blur(20px) saturate(180%);
border-top: 1px solid rgba(255, 255, 255, 0.4); /* bord supérieur brillant = lumière attrapant le matériau */
}
13. Retour d'information multimodal — mouvement + son + retour haptique
Trois règles pour combiner les sens (d'après Designing Audio-Haptic Experiences) :
- Causalité — il doit être évident ce qui a causé le retour d'information. Déclenchez-le sur l'événement causal réel (le basculement du toggle, l'élément qui se met en place), et faites correspondre son caractère à la physicalité de l'action.
- Harmonie — le visuel, le son et le retour haptique doivent se déclencher sur la même image. La latence entre eux détruit l'illusion. Ne laissez pas un décalage temporel gâcher l'immersion.
- Inévitabilité — le retour d'information doit se produire. Si le son ou le haptique est occasionnellement perdu (batterie faible, son coupé, écran silencieux), l'utilisateur ressent un manque de fiabilité. Concevez pour la redondance entre les canaux sensoriels.
14. Réduction de mouvement — l'animation doit s'adapter à chaque utilisateur
Les troubles vestibulaires, la cinétose et les préférences en matière de focalisation rendent l'animation excessive nuisible. Concevez en partant d'un état de repos plus sûr, puis ajoutez du mouvement, pas l'inverse.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
Cartographiez la réduction de mouvement comme suit :
- Les mouvements non essentiels (fondus, apparitions progressives, translations décoratives) → pas de mouvement (lieu d'arrivée immédiate, ou entièrement piloté par le défilement).
- L'expansion/contraction de contenu (fermeture/ouverture d'un accordéon, agrandissement d'une carte) → les valeurs finales apparaissent instantanément, mais les transformations de cadrage se font avec un amortissement très rapide et en sourdine.
- Défilement et glissement pilotés par geste — gardez le suivi 1:1, mais remplacez les rebonds/ressorts de momentum par un amortissement critique ou une vitesse fixe lente.
15. Ancrages de conception — assemblage des pièces
Les sections ci-dessus ne sont pas une liste de contrôle — elles forment un système. Voici comment elles s'assemblent dans des modèles courants :
| Composant | Principes clés |
|---|---|
| Bouton | Réponse instantanée (§1), retour en pressant, pas au toucher |
| Tiroir / panneau latéral | Suivi 1:1 lors du glissement (§2), ressort interruptible (§3), projection de momentum (§6), rubber-banding à la limite (§9), chemin symétrique (§7) |
| Feuille modale | Origine ancrée au déclencheur (§7), matériau translucide avec flou (§12), retour haptique sur la confirmation |
| Carrousel | Projection de momentum (§6), vélocité de transmission (§5), glissement 1:1, dimension X indépendante (§3) |
| Toggle | Mouvement de ressort depuis la valeur actuelle avec amortissement (§4, §3), son + haptique sur le déclencheur causal |
| Barre d'outils / navigation | Translucide, défilement en dessous, pas de contour opaque (§12) |