<audio>, <video> und <img> haben in Svelte eingebaute Bindings für ihre wichtigsten Eigenschaften. Damit lassen sich Custom-Player ohne großen Aufwand bauen — Wiedergabe steuern, aktuelle Position lesen, Lautstärke synchronisieren oder native Bildmaße ermitteln. Dieser Artikel zeigt alle verfügbaren Media-Bindings und ein vollständiges Mini-Player-Beispiel.

Two-Way-Bindings für Audio und Video

BindingBeschreibung
bind:currentTimeAktuelle Wiedergabe-Position (Sek.)
bind:playbackRateGeschwindigkeit (1 = normal)
bind:pausedtrue wenn pausiert
bind:volumeLautstärke 0–1
bind:mutedStumm

Diese Werte lassen sich lesen und schreiben: Wer paused = false setzt, startet die Wiedergabe.

svelte Einfacher Custom-Player
<script>
    let paused = $state(true);
    let currentTime = $state(0);
    let duration = $state(0);
    let volume = $state(1);
</script>

<audio
    src="/audio/sample.mp3"
    bind:paused
    bind:currentTime
    bind:duration
    bind:volume
></audio>

<button onclick={() => paused = !paused}>
    {paused ? 'Play' : 'Pause'}
</button>

<input type="range" bind:value={currentTime} min="0" max={duration} step="0.1" />
<span>{currentTime.toFixed(1)} / {duration.toFixed(1)} s</span>

<input type="range" bind:value={volume} min="0" max="1" step="0.01" />

Beachten: volume = 1.5 setzt natürlich nichts — der Browser cappt automatisch auf 1.

Read-only-Bindings

Diese Werte werden vom Browser bestimmt und können nur gelesen werden:

BindingBeschreibung
bind:durationGesamtdauer in Sekunden
bind:bufferedTimeRanges der gepufferten Bereiche
bind:seekableTimeRanges der seekbaren Bereiche
bind:seekingtrue während eines Seek
bind:endedtrue wenn Ende erreicht
bind:readyState04 (HAVE_NOTHINGHAVE_ENOUGH_DATA)
bind:playedTimeRanges der bereits abgespielten Teile

Diese sind trotzdem reaktiv: Wenn der Browser sie ändert (z. B. weil mehr Daten geladen sind), aktualisiert sich die Variable automatisch.

Video-spezifische Bindings

Bei <video> zusätzlich:

BindingBeschreibung
bind:videoWidthNative Videobreite (px)
bind:videoHeightNative Videohöhe (px)

Vor dem ersten Frame sind beide 0. Sobald Metadaten geladen sind, stehen die Werte zur Verfügung.

svelte Video mit Größenanzeige
<script>
    let videoWidth = $state(0);
    let videoHeight = $state(0);
</script>

<video
    src="/clip.mp4"
    controls
    bind:videoWidth
    bind:videoHeight
></video>

{#if videoWidth > 0}
    <p>Auflösung: {videoWidth} × {videoHeight}</p>
{/if}

Bilder: naturalWidth und naturalHeight

Bei <img> lassen sich die nativen Bildmaße auslesen — die unskalierten Original-Pixel-Werte:

svelte Bild mit nativer Größe
<script>
    let naturalWidth = $state(0);
    let naturalHeight = $state(0);
</script>

<img
    src="/photo.jpg"
    alt=""
    style="width: 200px"
    bind:naturalWidth
    bind:naturalHeight
/>

{#if naturalWidth > 0}
    <p>Original: {naturalWidth} × {naturalHeight} px</p>
{/if}

naturalWidth ist 0, bis das Bild geladen ist — dann reaktiv aktualisiert.

Vollständiger Custom-Audio-Player

svelte AudioPlayer.svelte
<script>
    let { src } = $props();

    let paused = $state(true);
    let currentTime = $state(0);
    let duration = $state(0);
    let volume = $state(1);
    let muted = $state(false);

    function format(seconds) {
        const m = Math.floor(seconds / 60);
        const s = Math.floor(seconds % 60).toString().padStart(2, '0');
        return `${m}:${s}`;
    }
</script>

<audio
    {src}
    bind:paused
    bind:currentTime
    bind:duration
    bind:volume
    bind:muted
></audio>

<div class="player">
    <button onclick={() => paused = !paused} aria-label={paused ? 'Play' : 'Pause'}>
        {paused ? '>' : '||'}
    </button>

    <input
        type="range"
        bind:value={currentTime}
        min="0"
        max={duration}
        step="0.1"
        aria-label="Position"
    />

    <span>{format(currentTime)} / {format(duration)}</span>

    <button onclick={() => muted = !muted} aria-label={muted ? 'Unmute' : 'Mute'}>
        {muted ? 'off' : 'on'}
    </button>

    <input
        type="range"
        bind:value={volume}
        min="0"
        max="1"
        step="0.01"
        aria-label="Lautstärke"
    />
</div>

<style>
    .player { display: flex; gap: 0.5em; align-items: center; }
</style>

Kein einziger addEventListener-Aufruf, keine eigene State-Logik — Svelte macht alles über die Bindings.

Beispiel: Auto-Play wenn sichtbar

svelte Video automatisch starten
<script>
    let paused = $state(true);
    let video;

    $effect(() => {
        if (!video) return;

        const observer = new IntersectionObserver(([entry]) => {
            paused = !entry.isIntersecting;
        });

        observer.observe(video);
        return () => observer.disconnect();
    });
</script>

<video bind:this={video} bind:paused src="/clip.mp4" muted loop></video>

bind:paused und bind:this zusammen — das Video startet, sobald es im Viewport ist, und pausiert bei Ausscrollen.

Häufige Stolperfallen

duration = 0 direkt nach Mount. Der Wert ist erst gesetzt, wenn die Metadaten geladen sind. Mit {#if duration > 0}...{/if} schützen.

paused = false ohne User-Interaction. Browser blockieren oft Auto-Play von Audio. Stummgeschaltetes Video (muted) funktioniert meist; Audio braucht Nutzer-Geste.

currentTime als Float ungenau anzeigen. {currentTime} zeigt z. B. 12.345678901. Mit currentTime.toFixed(1) formatieren.

Bindings funktionieren nicht beim ersten Render. Erst nachdem das Element im DOM ist und Metadaten geladen sind. Bei kritischer Logik im $effect arbeiten und Werte prüfen.

bind:duration schreiben. Geht nicht — Read-only-Binding. Compiler zeigt eine Warnung.

Weiterführende Ressourcen

Externe Quellen

Verwandte Artikel

/ Weiter

Zurück zu Bindings

Zur Übersicht