Apple Design
Erste Antwort
Wenn diese Fertigkeit zum ersten Mal ohne eine spezifische Frage aufgerufen wird, antworte nur mit:
Ich bin bereit, dir beim Erstellen von flüssigen, Apple-inspirierten Oberflächen im Web zu helfen. Mein Wissen stammt aus Apples WWDC-Designvorträgen, übersetzt für das Web.
Gib keine weiteren Informationen, bis der Benutzer eine Frage stellt.
Wie Apple Oberflächen baut, die aufhören, sich wie ein Computer anzufühlen, und sich anfühlen, als wären sie eine Erweiterung deiner selbst. Dieses Wissen stammt aus Apples WWDC-Designvorträgen – hauptsächlich Designing Fluid Interfaces (WWDC 2018) – destilliert und übersetzt für die Webplattform (CSS, Pointer Events, requestAnimationFrame, Spring-Bibliotheken wie Motion/Framer Motion).
Der rote Faden: Eine Oberfläche fühlt sich lebendig an, wenn die Bewegung vom aktuellen Bildschirmwert ausgeht, die Geschwindigkeit des Benutzers übernimmt, den Impuls nach vorne projiziert und jederzeit gegriffen und umgekehrt werden kann. Federn sind das Werkzeug, das all dies natürlich macht, da sie von Natur aus unterbrechbar und geschwindigkeitsbewusst sind.
Die Kernidee
"Wenn wir die Oberfläche an die Art und Weise anpassen, wie wir denken und uns bewegen, geschieht etwas Magisches – sie hört auf, sich wie ein Computer anzufühlen, und beginnt sich wie eine nahtlose Erweiterung von uns anzufühlen."
Eine Oberfläche ist flüssig, wenn sie sich wie die physische Welt verhält: Dinge reagieren sofort, bewegen sich kontinuierlich, tragen Schwung, widerstehen an Grenzen und können mitten in der Bewegung umgelenkt werden. Alles untenstehende ist ein Weg, um dem näher zu kommen.
Apple gestaltet Design so, dass es vier menschliche Bedürfnisse erfüllt: Sicherheit/Vorhersagbarkeit, Verständnis, Leistung und Freude. Jede hier aufgeführte Regel dient einem von ihnen.
1. Reaktion – Latenz töten
Sobald eine Verzögerung auftritt, fällt das Gefühl der Direktheit "von einer Klippe." Reaktion ist die Grundlage, auf der alles andere aufbaut.
- Reagiere beim Herunterdrücken des Zeigers, nicht beim Loslassen. Hebe einen Knopf in dem Moment hervor, in dem er gedrückt wird. Das Warten auf
click/Berührungsende, um Feedback zu zeigen, wirkt leblos. - Sei wachsam gegenüber jeder Latenz. Überprüfe Entprellungen, künstliche Timer, Übergangsverzögerungen und die ~300 ms Tippverzögerung. Alles auf dem Eingabepfad, was nicht unbedingt nötig ist, ist ein Rückschritt.
- Feedback muss während der Interaktion kontinuierlich sein, nicht nur am Ende. Ziehe bei einem Drag, Schieberegler oder einer Schublade die Benutzeroberfläche 1:1 mit dem Zeiger während des gesamten Vorgangs mit – animiere niemals nur, wenn die Geste abgeschlossen ist.
/* Feedback lebt beim Drücken und ist sofort */
.button:active {
transform: scale(0.97);
transition: transform 100ms ease-out;
}
2. Direkte Manipulation – 1:1-Verfolgung
"Berührung und Inhalt sollten sich gemeinsam bewegen."
Wenn der Benutzer etwas zieht, muss es am Finger kleben bleiben – und den Versatz von der Stelle respektieren, an der es gegriffen wurde. Das Einrasten in der Mitte des Elements beim Greifen zerstört sofort die Illusion.
- Verwende Pointer Events mit
setPointerCapture, damit die Verfolgung fortgesetzt wird, auch wenn der Zeiger die Grenzen des Elements verlässt. - Verfolge eine kurze Geschwindigkeits-/Positionshistorie (die letzten paar
pointermove-Ereignisse), nicht nur den aktuellen Punkt – du wirst beim Loslassen die Geschwindigkeit benötigen.
el.addEventListener('pointerdown', (e) => {
el.setPointerCapture(e.pointerId);
const grabOffset = e.clientY - el.getBoundingClientRect().top; // respektiere, wo gegriffen wurde
// ...Position + Zeitstempelhistorie für Geschwindigkeit verfolgen
});
3. Unterbrechbarkeit – das wichtigste Prinzip überhaupt
"Der Gedanke und die Geste geschehen parallel."
Jede Animation muss unterbrechbar und jederzeit umlenkbar sein. Ein Benutzer muss in der Lage sein, ein sich bewegendes Element mitten im Flug zu greifen und umzukehren, ohne auf das Ende der Animation warten zu müssen. Ein schließender Modal, den der Benutzer erneut greift, sollte dem Finger folgen – nicht zuerst schließen und dann wieder öffnen.
- Sperre niemals die Eingabe während eines Übergangs.
- Animiere immer vom aktuellen (Anzeige-)Wert, niemals vom Zielwert. Bei einer Unterbrechung lies die live auf dem Bildschirm angezeigte Transformation des Elements und starte die neue Animation von dort. Der Start vom logischen/Zielwert führt zu einem sichtbaren Sprung.
- Vermeide CSS-Übergänge und
@keyframesfür alles, was von Gesten gesteuert wird – sie können nicht reibungslos mitten im Flug gegriffen und umgekehrt werden. Federn animieren standardmäßig vom aktuellen Wert, was genau das ist, was eine Unterbrechung benötigt. - Wenn eine Geste umkehrt, überblende die Geschwindigkeit – mache keinen harten Schnitt. Das Ersetzen einer Animation durch eine andere bei einer Umkehrung erzeugt eine Diskontinuität in der Geschwindigkeit, eine "Betonmauer." Federbibliotheken, die die Geschwindigkeit durch eine Neuausrichtung tragen, vermeiden dies. (Dies ist, was iOS' additive Animationen nativ tun; wähle im Web eine Federbibliothek, die mit der aktuellen Geschwindigkeit neu ausrichtet.)
- Zerlege 2D-Bewegung in unabhängige X- und Y-Federn. Eine einzelne Feder auf einer 2D-Distanz desynchronisiert, wenn X und Y unterschiedliche Geschwindigkeiten haben.
4. Verhalten über Animation – verwende Federn
"Denke an Animation als ein Gespräch zwischen dir und dem Objekt, nicht als etwas, das von der Oberfläche vorgeschrieben wird."
Eine vorgeplante Animation mit fester Dauer kann nicht auf neue Eingaben reagieren. Eine Feder kann – neue Eingaben ändern einfach das Ziel, und die Bewegung bleibt kontinuierlich. Greife für alles, was ein Benutzer berühren kann, zu Federn.
Apple hat bewusst das physikalische Tripel (Masse/Steifigkeit/Dämpfung) durch zwei designerfreundliche Parameter ersetzt. Denke in diesen:
- Dämpfungsverhältnis – steuert Überschwinger.
1,0= kritisch gedämpft, kein Hüpfen, sanftes Einpendeln.< 1,0= überschwingt und oszilliert. Niedriger = hüpfriger. - Ansprechzeit – wie schnell der Wert das Ziel erreicht, in Sekunden. Niedriger = schneller. Dies ist nicht die "Dauer" – eine Feder hat keine feste Dauer; ihre Einpendelzeit ergibt sich aus den Parametern.
Standardwerte:
- Starte die meisten UI-Elemente mit Dämpfung
1,0(kritisch gedämpft) – elegant und nicht ablenkend. - Füge Hüpfen (Dämpfung ~
0,8) nur dann hinzu, wenn die Geste selbst Schwung hatte (ein Wischen, ein Werfen, ein Loslassen nach einem Zug). Überschwinger bei einem Menü, das gerade eingeblendet wurde, fühlen sich falsch an; Überschwinger bei einer Karte, die du geworfen hast, fühlen sich richtig an.
Konkrete Werte, die Apple ausliefert:
| Interaktion | Dämpfung | Ansprechzeit |
|---|---|---|
| Bewegen / Neupositionieren (z.B. PiP) | 1,0 | 0.4 |
| Drehung | 0,8 | 0.4 |
| Schublade / Sheet | 0,8 | 0.3 |
Web-Zuordnung (Motion / Framer Motion): Die bounce + duration Spring-API ähnelt stark Apples Dämpfung + Ansprechzeit. Ein sicherer Hausstil ist die standardmäßige Verwendung von damping: 1,0-Federn überall; reserviere Hüpfen für schwungvolle, physikalische Interaktionen.
import { animate } from 'motion';
// Kritisch gedämpfter Standard (kein Überschwinger)
animate(el, { y: 0 }, { type: 'spring', bounce: 0, duration: 0.4 });
// Schwung-Interaktion – ein wenig Hüpfen, nur weil ein Wischen vorausging
animate(el, { y: target }, { type: 'spring', bounce: 0.2, duration: 0.4 });
5. Geschwindigkeitsübergabe – die Naht zwischen Ziehen und Animation
Wenn eine Geste endet, muss die Animation mit der exakten Geschwindigkeit des Fingers fortgesetzt werden, damit keine sichtbare Naht zwischen Ziehen und Animieren entsteht. Dies ist das Detail, das am meisten "flüssig" von "in Ordnung" trennt.
Übergib die Loslassgeschwindigkeit des Zeigers als Anfangsgeschwindigkeit der Feder. Einige Feder-APIs möchten eine relative Geschwindigkeit – normalisiere sie durch die verbleibende Distanz zum Ziel:
relativeGeschwindigkeit = GestenGeschwindigkeit / (ZielWert − AktuellerWert)
Beispiel: Element bei y=50, Ziel y=150 (100px zu gehen), Finger bewegt sich mit 50px/s → Anfangsgeschwindigkeit der Feder = 50 / 100 = 0,5. Framer Motion / Motion akzeptieren die absolute Geschwindigkeit in px/s direkt (velocity-Option), daher übergibst du normalerweise den rohen Wert.
6. Impulsprojektion – animiere dorthin, wo die Geste hingeht
"Nimm eine kleine Eingabe und mache eine große Ausgabe."
Schnappe nicht zur nächsten Grenze vom Loslasspunkt aus. Verwende die Geschwindigkeit, um die Ruheposition zu projizieren – genau wie beim Scroll-Auslauf – und schnappe dann zu dem Ziel, das diesem projizierten Punkt am nächsten ist. Dies ist es, was ein Wischen sich anfühlen lässt, als würde es das Element werfen.
Apples exakte Projektionsfunktion (aus dem Beispielcode von Designing Fluid Interfaces):
// decelerationRate ≈ 0,998 für normales Scrollgefühl; 0,99 für schnelleres
function project(initialVelocity /* px/s */, decelerationRate = 0.998) {
return (initialVelocity / 1000) * decelerationRate / (1 - decelerationRate);
}
const projectedEndpoint = currentPosition + project(releaseVelocity);
const target = nearestSnapPoint(projectedEndpoint); // wähle Ziel aus der Projektion
animateSpringTo(target, { velocity: releaseVelocity }); // übergib dann die Geschwindigkeit (§5)
Hinweis: Die physiklehrbuchhafte v²/(2·decel)-Formel ist nicht das, was Apple ausliefert – verwende die obige exponentielle Abklingform. Dies ist das Standardverhalten in guten Bottom-Sheets und Karussells (Vaul, Embla).
7. Räumliche Konsistenz – symmetrische Pfade, verankerte Ursprünge
"Wenn etwas auf einem Weg verschwindet, erwarten wir, dass es von dort auftaucht, wo es herkam."
- Betrete und verlasse entlang desselben Pfades. Ein Panel, das von rechts hereingleitet, muss nach rechts verschwinden. Von-rein-rechts / raus-unten fühlt sich abgekoppelt und verwirrend an.
- Verankere Interaktionen an ihrer Quelle. Ein Menü, Popover oder Sheet sollte von dem Element ausgehen, das es ausgelöst hat – setze
transform-originauf den Auslöser, damit die räumliche Beziehung zwischen Schaltfläche und Inhalt offensichtlich ist. (Dies ist derselbe Punkt der Ursprungsbewusstheit wie bei Popovers, die von ihrem Auslöser aus skaliert werden, nicht von ihrer Mitte.) - Spiegle die Beschleunigung bei reversiblen Übergängen, damit der ausgehende Pfad mit dem zurückkehrenden Pfad übereinstimmt (verwende inverse kubische Bézier-Kontrollpunkte für die beiden Richtungen).
8. Deute in die Richtung der Geste
Menschen sagen einen Endzustand aus einer Flugbahn voraus. Die Zwischenbewegung sollte telegraphieren, wohin die Dinge gehen – Control-Center-Module "wachsen nach oben und außen in Richtung deines Fingers." Mache die Zwischenbilder so, dass sie auf das Ergebnis zeigen, anstatt nur blind dorthin zu interpolieren.
9. Gummi-Effekt – weiche Grenzen
Widerstehe an einer Grenze progressiv, anstatt hart zu stoppen. Ein harter Stopp liest sich wie "eingefroren"; ein kontinuierlicher Widerstand liest sich wie "reagiert, aber hier gibt es nichts mehr." Wende eine Dämpfung an, die zunimmt, je weiter der Benutzer über die Grenze hinaus zieht.
// Je weiter über die Grenze hinaus, desto weniger folgt das Element – reale Dinge verlangsamen, bevor sie anhalten
function rubberband(overshoot, dimension, constant = 0.55) {
return (overshoot * dimension * constant) / (dimension + constant * Math.abs(overshoot));
}
10. Details des Gestendesigns (die "Gefühls"-Checkliste)
- Tippen: Hervorheben beim Herunterdrücken (sofort), ausführen beim Losheben. Füge etwa 10px Hysterese/Trefferpolsterung um das Ziel hinzu und erlaube Abbruch durch Wegziehen und Zurückkommen.
- Ziehen/Wischen: Erfordere eine kleine Bewegungsschwelle (Hysterese, ~10px), bevor du dich auf eine Richtung festlegst, und verfolge dann 1:1.
- Erkenne alle plausiblen Gesten parallel ab der ersten Bewegung und breche dann selbstbewusst die Verlierer ab, sobald die Absicht klar ist. Vermeide Erkennungsmechanismen, die nur einen endgültigen Zustand melden (
swipeleft-artige Ereignisse) – sie werfen die kontinuierliche Verfolgung weg, die du für Feedback benötigst. - Minimiere Verzögerungen durch Disambiguierung. Die Erkennung von Doppeltipps verzögert unvermeidlich einzelne Tipps; zahle diesen Preis nur dort, wo Doppeltipps wirklich existieren.
11. Bildgenaue Glätte
Glätte betrifft das, was in den Bildern ist, nicht nur die Bildrate.
- Halte die positionsbezogene Änderung pro Bild unter der Wahrnehmungsschwelle, um ein Stroboskopieren zu vermeiden.
- Für sehr schnelle Bewegungen kodiert eine subtile Bewegungsunschärfe / Dehnung die Geschwindigkeit und liest sich besser als ein harter, scharfer Strich.
requestAnimationFrameist die anzeigesynchronisierte Uhr des Webs (Apple verwendetCADisplayLink). Animiere nur compositor-freundliche Eigenschaften –transformundopacity– und deute mitwill-changean, wo Bewegung bevorsteht.
12. Materialien & Tiefe – Transluzenz vermittelt Hierarchie
Apple verwendet transluzente Materialien als schwebende funktionale Schicht, die Struktur bringt, ohne die Aufmerksamkeit zu stehlen. Nähere dich im Web mit backdrop-filter an.
- Baue Nav-/Toolbars/Sheets als transluzente Schichten (
backdrop-filter: blur()+ ein halbtransparenter Hintergrund), bei denen der Inhalt darunterscrollt – nicht undurchsichtige Balken, die einen festen Streifen verbrauchen. - Das Materialgewicht kodiert die Hierarchie: dunklere/schwerere Materialien trennen strukturelle Regionen (Seitenleisten); hellere Materialien lenken die Aufmerksamkeit auf interaktive Elemente (Schaltflächen). Staple niemals eine helle transluzente Fläche auf eine andere – die Lesbarkeit bricht zusammen.
- Größere Flächen sollten als dicker wahrgenommen werden: stärkere Unschärfe + ein tieferer Schatten als bei kleinen Chips. Ziehe kontextbewusste Schatten in Betracht – schwerer über belebten/Textinhalten zur Trennung, leichter über schlichten Hintergründen.
- Abdunkeln zum Fokussieren, Trennen zum Fließen lassen. Ein modaler Task paart die Oberfläche mit einem abdunkelnden Vorhang und drückt den Hintergrund zurück/nach unten. Ein paralleles, nicht blockierendes Panel verwendet Transluzenz und Versatz ohne einen Vorhang, damit der Fluss nicht unterbrochen wird. Bei gestapelten Sheets dunkle und drücke jede übergeordnete Ebene progressiv ab.
- Vibrancy hält Text über wechselnden Hintergründen lesbar. Verwende über unscharfen/transluzenten Oberflächen kein flaches Grau für Text – verwende stattdessen höheren Kontrast, ein etwas schwereres Gewicht und eine kleine Erhöhung des Buchstabenabstands. Platziere Farbe auf einer soliden Schicht, nicht im transluzenten Vordergrund.
- Scrolle Randeffekte, keine harten Trennlinien. Anstelle eines 1px-Rands unter einem klebrigen Header blende eine kleine Unschärfe-/Verlaufsmaske ein, wo Inhalt auf schwebendes Chrom trifft – nur dort, wo schwebende UI tatsächlich Inhalt überlappt.
- Materialisiere, verblasse nicht nur. Verwandle bei Glas-/Unschärfeflächen den Unschärferadius und die Skalierung gemeinsam beim Ein-/Ausgang, damit die Oberfläche als ein ankommendes reales Material gelesen wird und nicht als einfacher Deckkraftübergang.
.toolbar {
background: rgba(255, 255, 255, 0.6);
backdrop-filter: blur(20px) saturate(180%);
border-top: 1px solid rgba(255, 255, 255, 0.4); /* helle Oberkante = Licht, das auf das Material fällt */
}
13. Multimodales Feedback – Bewegung + Klang + Haptik
Drei Regeln für die Kombination der Sinne (aus Designing Audio-Haptic Experiences):
- Kausalität – es muss offensichtlich sein, was das Feedback verursacht hat. Löse es beim tatsächlichen kausalen Ereignis aus (das Umlegen des Schalters, das Einrasten des Elements) und passe seinen Charakter an die Physis der Aktion an.
- Harmonie – das Visuelle, der Klang und die Haptik müssen im selben Bild ausgelöst werden. Latenz zwischen ihnen zerstört die Illusion. Lass nicht zu, dass eine
…
[gekürzt für die Übersetzung]