Zum Inhalt springen
UI Kit
Accent

Bereiche

Scroll-Geschichten und Scroll-Effekte

Sections, die beim Scrollen erzählen. Jede rendert zuerst ihr fertiges Layout, ist ohne JavaScript lesbar und ruht bei reduzierter Bewegung.

Auf dieser Seite

Die passende Szene#

Scroll-Geschichten und Scroll-Reisen erzählen über mehrere Bildschirme, eine Section hält an, und der Inhalt ändert sich mit dem Scrollen.

ComponentVariantenWofür
sticky-stackfeatures, process, case-studies, split, pileKarten stapeln sich beim Scrollen, die verdeckte tritt zurück.
sideways-scrollcards, timeline, gallery, chapters, productsEine Reihe wandert seitwärts, während die Seite nach unten scrollt.
zoom-revealimage, product, video, grid, app-iconEin Bild oder Produkt wächst von klein bis zum ganzen Fenster.
pinned-mediafullbleed, pan-zoom, wipe, reel, deviceEin Medium bleibt stehen, während daneben Kapitel wechseln.
number-journeycount, bar, flip, compare, ringEine große Zahl reist durch Stationen.
image-sequencespin, exploded, daylight, growEin gezeichnetes Bild, das sich wie ein Daumenkino Bild für Bild ändert.
path-journeyroute, delivery, cycle, ascentEine Markierung reist einen Weg entlang, der sich selbst zeichnet.

Scroll-Effekte sowie Reveals und Übergänge sind kürzer. Sie machen einen Übergang oder eine Überschrift unverwechselbar und geben die Seite schnell wieder frei.

ComponentVariantenWofür
split-revealdoors, shutter, diagonal, ticket, slatsTeile öffnen sich und zeigen, was dahinter liegt.
parallax-layerslandscape, product, collage, typeEbenen bewegen sich unterschiedlich schnell.
text-scrublines, converge, scale, stack, outlineGroße Schrift bewegt sich genau mit dem Scrollen.
card-fanhand, spread, arc, deck, photosKarten fächern sich auf, verteilen sich und stapeln sich.
mask-revealheadline, zoom-through, lines, numbersSchrift als Fenster auf ein Bild.
section-transitionsdark-band, accent-wash, curtain, circle, card-shrinkWie eine Section an die nächste übergibt.

Eine Szene einsetzen#

Szenen nehmen Inhalte über Props wie jede Component. Bilder kommen als media oder items[].media, Kapitel als Liste. In Astro bekommt eine Szene eine client-Direktive, damit sie beim Scrollen läuft.

StickyStack, Variante processIn Components ansehen
import { StickyStack } from '@/components/ui/sticky-stack';
import { PinnedMedia } from '@/components/ui/pinned-media';

<StickyStack
  variant="process"
  title="Vom ersten Gespräch bis zum Start"
  items={[
    { eyebrow: 'Woche 1', title: 'Workshop', text: 'Wir ordnen Ziele, Seiten und Inhalte an einem Nachmittag.' },
    { eyebrow: 'Woche 2', title: 'Design', text: 'Drei Screens in deinen Farben, fertig zum Klicken.' },
    { eyebrow: 'Woche 4', title: 'Start', text: 'Live auf deiner Domain, mit Statistik und Übergabe.' },
  ]}
/>

<PinnedMedia
  variant="pan-zoom"
  title="Ein Rundgang durch die Bäckerei"
  media={<img src="/bakery-plan.avif" alt="Grundriss der Bäckerei Lindner" width={1600} height={1000} />}
  chapters={[
    { title: 'Der Ofen', text: 'Steinofen, jeden Morgen um vier angeheizt.', focus: { x: 0.28, y: 0.4, zoom: 1.8 } },
    { title: 'Die Theke', text: 'Zwanzig Sorten Brot, geschnitten, während du wartest.', focus: { x: 0.7, y: 0.62, zoom: 1.5 } },
  ]}
/>
src/pages/index.astro
<!-- Ohne Direktive steht die fertige, ruhige Fassung da -->
<StickyStack variant="process" items={items} />

<!-- Mit Direktive läuft die Szene beim Scrollen -->
<PinnedMedia client:visible variant="pan-zoom" chapters={chapters} media={media} />

In der Vorschau#

Auf der Seite einer Kategorie bekommt die Vorschau einer Szene eine feste Fensterhöhe und scrollt in sich selbst, so laufen Stapel, Kapitel und Zoom genau wie auf deiner Seite. Scroll dafür mit der Maus oder dem Trackpad über der Vorschau.

Eine Vorschau erkennt Szenen an data-kit-viewport. Die Szenen reichen jedes zusätzliche Attribut an ihr äußeres Element weiter, so markierst du auch eigene Demos.

Reduzierte Bewegung und ohne JavaScript#

Jede Szene rendert auf dem Server ihr fertiges Layout. Ohne JavaScript und bei reduzierter Bewegung bleibt es dabei, alle Kapitel, Bilder und Zahlen stehen untereinander und sind vollständig lesbar. Was nur durch Bewegung verständlich wäre, bekommt dort eine eigene ruhige Form, etwa eine Reihe, die man selbst seitlich wischt, statt der geführten Fahrt.

Auf dem Telefon haben viele Szenen ein eigenes Layout, etwa eine Wischreihe statt der seitlichen Fahrt oder einen Zeitstrahl nach unten. Links in späten Kapiteln bleiben in der Tab-Reihenfolge, und Szenen mit gepinnter Strecke scrollen dann an die passende Stelle.

Leistung#

  • Der Fortschritt läuft als CSS-Variable --p, nicht über React-State. Ein Scroll-Frame löst kein Rendern aus.
  • Bewegt werden nur transform, opacity und clip-path, nie etwas, das das Layout verschiebt.
  • Höhen gepinnter Strecken werden beim Start und bei Größenänderung gemessen, nicht beim Scrollen.
  • Szenen mit gezeichneten Bildern halten die Variable an kleinen Elementen ohne Bild, damit das Bild nicht bei jedem Frame neu gemalt wird.
  • Gib Bildern feste width und height und ein leichtes Format wie AVIF, eine gepinnte Szene zeigt sie lange und groß.

Eine eigene Szene#

Alle Szenen teilen sich scroll-scene. Dieselben Helfer tragen auch eine eigene, kleine Szene.

src/components/Statement.tsx
import { useLive, useSceneProgress, seg } from '@/components/ui/scroll-scene';

export function Statement() {
  // Läuft erst im Browser, ab Tablet und ohne reduzierte Bewegung
  const live = useLive('(min-width: 768px)');
  // Schreibt den Fortschritt 0 bis 1 als --p an das Element
  const ref = useSceneProgress<HTMLElement>(live, { mode: 'enter' });
  return (
    <section ref={ref} className="py-24">
      <h2 style={{ opacity: `calc(0.25 + 0.75 * ${seg(0, 0.7)})`, transform: `translateY(calc((1 - ${seg(0, 0.7)}) * 24px))` }}>
        Brot braucht Zeit. Wir auch.
      </h2>
    </section>
  );
}
HelferGibt zurückWofür
useLive(query?)booleanWahr, sobald die Szene laufen darf, im Browser, mit erlaubter Bewegung und passender Media Query.
useSceneProgress(live, opts)RefSchreibt den Fortschritt bei jedem Scroll-Frame in eine CSS-Variable, ohne React-Render. Modi 'pin', 'pass' und 'enter'.
seg(a, b)stringCSS-Ausdruck, der von 0 bis 1 läuft, während der Fortschritt von a bis b läuft. Ohne JavaScript fertig.
span, smooth, lerpnumberDasselbe in JavaScript, für Szenen, die Transforms direkt schreiben.
scrollToProgress(track, p)voidBringt eine gepinnte Strecke auf einen Fortschritt, für Links, die man mit Tab erreicht.

Die Grundregeln für Bewegung im Kit stehen unter Motion.

Oft gesucht

Direkt zu

In die Zwischenablage kopiert