Que fait Conception Apple ?
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 web fluides de style Apple. Mes connaissances proviennent des conférences de conception d'Apple à la WWDC, adaptées au web.
Ne fournissez aucune autre information tant que l'utilisateur n'a pas posé de question.
Comment Apple crée des interfaces qui cessent de ressembler à un ordinateur et commencent à ressembler à une extension de vous-même. Ces connaissances proviennent des conférences de conception 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 semble vivante lorsque le mouvement commence à partir de la valeur actuelle à l'écran, hérite de la vélocité de l'utilisateur, projette l'élan 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 lorsqu'elle se comporte comme le monde physique : les choses répondent instantanément, bougent en continu, portent un élan, 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 la conception comme répondant à quatre besoins humains : sécurité/prévisibilité, compréhension, accomplissement et joie. Chaque règle ici sert l'un d'eux.
1. Réponse — éliminer la latence
Dès que la latence apparaît, la sensation de naturel « chute de la falaise ». La réponse est le fondement sur lequel tout le reste est construit.
- Répondre dès le pointeur enfoncé, pas au relâchement. Mettez en surbrillance un bouton dès qu'il est pressé. Attendre l'événement
click/touch-up pour afficher un retour donne une sensation de mort. - Soyez vigilant face à chaque latence. Auditez les debounces, les temporisateurs artificiels, 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 feedback doit être continu pendant l'interaction, pas seulement à la fin. Pour un glisser, un curseur ou un tiroir, mettez à jour l'interface 1:1 avec le pointeur tout au long du parcours — n'animez jamais uniquement lorsque le geste se termine.
/* Le feedback vit sur l'appui, 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ù ils l'ont saisi. 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 relâchement.
el.addEventListener('pointerdown', (e) => {
el.setPointerCapture(e.pointerId);
const grabOffset = e.clientY - el.getBoundingClientRect().top; // respecter où ils ont saisi
// ...suivre l'historique position + 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 modale en cours de fermeture que l'utilisateur saisit à nouveau doit suivre le doigt — pas d'abord finir de se fermer, puis se rouvrir.
- Ne verrouillez jamais l'entrée pendant une transition.
- Animez toujours à partir de la valeur actuelle (de présentation), jamais de la valeur cible. En cas d'interruption, lisez la transformation en direct à l'écran de l'élément et commencez la nouvelle animation à partir de là. Partir de la valeur logique/cible provoque un saut visible.
- Évitez les transitions CSS et
@keyframespour tout ce qui est piloté par les gestes — 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, mixez la vélocité — ne la coupez pas brusquement. Remplacer une animation par une autre à un point d'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 reciblage l'évitent. (C'est ce que les animations additives d'iOS font nativement ; sur le web, choisissez une bibliothèque de ressorts qui recible à 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 quelque chose de prescrit par l'interface. »
Une animation pré-scénarisée à durée fixe ne peut pas répondre à une nouvelle entrée. 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 adaptés aux concepteurs. Pensez en ces termes :
- Rapport d'amortissement — contrôle le dépassement.
1.0= amortissement critique, pas de rebond, stabilisation en douceur.< 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 vif. Ce n'est pas une « 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 interfaces avec un amortissement
1.0(amortissement critique) — élégant et non distrayant. - Ajoutez du rebond (amortissement ~
0.8) uniquement lorsque le geste lui-même a porté un élan (un flick, un lancer, un relâchement de glisser). 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éplacer / repositionner (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 + la réponse d'Apple. Un style de base sûr consiste à utiliser des ressorts avec damping: 1.0 partout par défaut ; réservez le rebond pour les interactions physiques pilotées par l'élan.
import { animate } from 'motion';
// Valeur par défaut à amortissement critique (pas de dépassement)
animate(el, { y: 0 }, { type: 'spring', bounce: 0, duration: 0.4 });
// Interaction avec élan — un peu de rebond, uniquement parce qu'un flick l'a précédé
animate(el, { y: target }, { type: 'spring', bounce: 0.2, duration: 0.4 });
5. Transfert de vélocité — la jointure entre le glisser et l'animation
Lorsqu'un geste se termine, l'animation doit continuer à la vélocité exacte du doigt, afin qu'il n'y ait pas de jointure visible entre le glisser et l'animation. C'est le détail qui distingue le plus « fluide » de « correct ».
Passez 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 (100 px à parcourir), doigt se déplaçant à 50 px/s → vélocité initiale du ressort = 50 / 100 = 0.5. Framer Motion / Motion acceptent directement la vélocité en px/s absolue (option velocity), donc vous lui donnez généralement la valeur brute.
6. Projection d'élan — animer vers l'endroit où le geste se dirige
« Prenez une petite entrée et faites-en 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 de 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 (extrait du code exemple de Designing Fluid Interfaces) :
// decelerationRate ≈ 0.998 pour une sensation de défilement normale ; 0.99 pour plus nerveux
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 transférer la vélocité (§5)
Remarque : la formule physique v²/(2·decel) 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 manière, nous nous attendons à 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. Entrée par la droite / sortie par le bas semble déconnecté et déroutant.
- 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 se déploient à 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 inversés pour les deux directions).
8. Suggérer dans la direction du geste
Les humains prédisent un état final à partir d'une trajectoire. Les images intermédiaires doivent télégraphier où les choses vont — les modules du Centre de contrôle « grandissent vers le haut et vers l'extérieur en direction de votre doigt. » Faites en sorte que les trames intermédiaires pointent vers le résultat, pas seulement qu'elles interpolent aveuglément vers celui-ci.
9. Effet de caoutchouc — limites souples
À une limite, résistez progressivement au lieu de vous arrêter brusquement. Un arrêt brutal donne l'impression d'être « gelé » ; une résistance continue donne l'impression d'être « réactif, mais il n'y a plus rien ici ». Appliquez un amortissement qui augmente à mesure que l'utilisateur dépasse la limite.
// Plus on dépasse la limite, moins l'élément suit — les choses réelles 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 vérification « sensation »)
- Tap : mise en surbrillance au toucher-enfoncé (instantané), validation au toucher-relâché. Ajoutez environ 10 px d'hystérésis/marge de hit autour de la cible, et autorisez l'annulation en glissant ailleurs et en revenant.
- Glisser/swipe : exigez un petit seuil de mouvement (hystérésis, ~10 px) avant de s'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 feedback. - Minimisez les délais de désambiguïsation. La détection du double-tap retarde inévitablement les taps simples ; ne payez ce coût que là où le double-tap existe réellement.
11. Fluidité au niveau de la trame
La fluidité concerne ce qu'il y a dans les trames, pas seulement la fréquence d'images.
- Maintenez le changement de position par trame en dessous du seuil de perception pour éviter l'effet de stroboscopie.
- Pour un mouvement très rapide, un flou de mouvement / étirement subtil encode la vitesse et est plus agréable à lire 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 suggérez avecwill-changelà où le mouvement est imminent.
12. Matériaux et profondeur — la translucidité véhicule la hiérarchie
Apple utilise des matériaux translucides comme couche fonctionnelle flottante qui apporte de la structure sans voler l'attention. Sur le web, approchez avec backdrop-filter.
- Créez des nav/bars d'outils/feuilles comme des couches translucides (
backdrop-filter: blur()+ un fond semi-transparent) avec le contenu défilant en dessous — pas des barres opaques qui consomment une bande fixe. - Le poids du matériau encode la hiérarchie : des matériaux plus sombres/plus lourds séparent les régions structurelles (barres latérales) ; des 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 donner l'impression d'être 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 chargé/bruyant pour la séparation, plus légère sur des fonds unis.
- Assombrissez pour concentrer, séparez pour garder le flux. Une tâche modale associe la surface à un voile d'assombrissement et repousse/abaisse l'arrière-plan. Un panneau parallèle non bloquant utilise la translucidité et le décalage sans voile 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 plat — 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 1 px sous un en-tête collant, fondez un petit masque de flou/gradient là où le contenu rencontre le chrome flottant — uniquement là où l'interface 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 à l'entrée/sortie, afin que la surface soit perçue comme un matériau réel qui arrive plutôt qu'une simple atténuation 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 lumineux = lumière attrapant le matériau */
}
13. Retour multimodal — mouvement + son + 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éclenchez-le sur l'événement causal réel (le basculement du toggle, l'élément qui s'encastre), et faites correspondre son caractère à la physicalité de l'action.
- Harmonie — le visuel, le son et l'haptique doivent se déclencher sur la même trame. La latence entre eux détruit l'illusion. Ne laissez pas un délai réseau ou un callback asynchrone retarder une sensation ; pré-calculez et pré-chargez le retour pour qu'il soit prêt à être émis dans la même trame que la mise à jour visuelle.
- Utilité — ne sonorisez pas les actions triviales (un simple tap). Réservez le son+haptique pour les moments à enjeux : verrouillage à un point d'ancrage, basculement d'un état binaire, seuils dépassés. Chaque sensation doit transmettre des informations qu'aucun autre sens ne peut fournir seul.
Sur le web : navigator.vibrate() pour les vibrations courtes et basiques ; utilisez des API audio Web Audio ou une bibliothèque de conception sonore pour un son spatial/causé. Gardez les trois verrouillés sur le même requestAnimationFrame — si le son ou la vibration ne peut pas être programmé sur la même trame, supprimez-le plutôt que de le jouer en retard.
14. Accessibilité — ne forcez jamais la sensation
« Le mouvement n'est pas le message — il amplifie le message. »
- Respectez
prefers-reduced-motion. Si l'utilisateur demande moins de mouvement, supprimez les animations décoratives et l'effet de ressort. Remplacez par un fondu/déplacement à durée fixe court ou, si ce n'est pas essentiel, un saut instantané. Ne retirez pas la fonctionnalité — la feuille doit toujours s'ouvrir, mais elle peut le faire avec un fondu de 200 ms au lieu d'un ressort de 0,4 s. - Respectez
prefers-color-schemepour la translucidité — un fond clair semi-transparent sur un thème sombre doit s'assombrir. Utilisez des couleurs de thème sémantiques, pas des valeurs codées en dur. - Respectez
prefers-contrast— à contraste plus élevé, réduisez la translucidité et l'effet de flou, optez pour des couleurs de fond plus solides et des bordures plus nettes. - Proposez toujours des alternatives non gestuelles. Toute action qui répond à un swipe/tap à deux doigts/maintenir doit aussi avoir un équivalent en clic ou clavier. Ne cachez pas les contrôles derrière des gestes.
- Gardez les gestes non essentiels facultatifs et détectables. Un geste qui n'a pas d'indice visuel (comme un triple-tap) doit être facultatif et/ou avoir un équivalent standard. Préférez les gestes qui ont une manifestation visuelle (glissement de tiroir, déplacement de carte).
15. Motion intent — arrêtez-vous là où la sensation se termine
Traquez la latence. Testez sur des appareils réels lents. Supprimez les animations non motivées. Chaque fois que vous ajoutez un mouvement, demandez : « Est-ce que cela sert la compréhension, l'accomplissement ou la joie ? » Si la réponse est « non », supprimez-le.
Le design fluide est un processus, pas une liste de contrôle — il nécessite de modifier les animations en fonction des performances du monde réel et des commentaires des utilisateurs.