Startseite / Artikel / Vermeidung von kumulativen Layout-Shifts mit Video-Hintergründen in Next.js

Vermeidung von kumulativen Layout-Shifts mit Video-Hintergründen in Next.js

Erlernen Sie praktische CSS- und Layout-Techniken, um zu verhindern, dass Hintergrundvideos in Next.js zu einem kumulativen Layout-Shift auf verschiedenen Geräten und bei unterschiedlichen Netzwerkgeschwindigkeiten führen.

1289 Wörter

Es gibt eine bestimmte Art von Frontend-Fehler, der unter idealen Bedingungen während der Entwicklung unsichtbar bleibt, doch sobald die Netzwerkverbindung eingeschränkt wird, verursacht das hinzugefügte Hintergrundvideo, dass die Seite unkontrolliert springt – wie in einer chaotischen Sitcom-Szene.

Herzlichen Glückwunsch: Sie haben soeben auf den Cumulative Layout Shift gestoßen.

Hintergrundvideos entgehen leicht der Überprüfung, weil sie im Hintergrund liegen, bei einer schnellen Verbindung einwandfrei funktionieren und Entwickler Videos in der Regel als rein visuellen Layer betrachten, anstatt als Elemente, die am Layout der Seite beteiligt sind.

Der Browser teilt unsere Annahmen jedoch nicht. Wenn die Größe eines Elements zum Zeitpunkt der ersten Darstellung unbekannt ist, muss der Browser raten. Und genau solche Schätzungen sollten nicht die Entscheidungen bezüglich des Layouts bestimmen.

Nun, da dieser Kontext geklärt ist, gehen wir zu den technischen Details über.

Die grundlegende Regel: Reservieren Sie den Platz vor dem Laden des Videos

Cumulative Layout Shift misst, wie stark sich sichtbarer Inhalt unerwartet verschiebt. Die einfachste Möglichkeit, dies zu vermeiden, besteht darin, den Medienelementen vor dem vollständigen Herunterladen der entsprechenden Ressourcen vorhersehbare, bekannte Abmessungen zuzuweisen. Durch das Festlegen einer expliziten Breite und Höhe oder die Verwendung der CSS-Eigenschaft aspect-ratio kann der Browser diesen Platz bereits im Voraus bei der Layout-Berechnung einplanen.

Einfach ausgedrückt: Reservieren Sie Platz für ein Element, bevor es tatsächlich dargestellt wird.

Für einen Hero-Bereich mit Hintergrundvideo ist ein guter Ausgangspunkt ein Container mit festen Abmessungen, anstatt zu erlauben, dass das <video>-Tag selbst bestimmt, wie groß der Hero-Bereich ist.

export function VideoHero() {
  return (
    <section className="relative min-h-[70svh] overflow-hidden">
      <video
        className="absolute inset-0 h-full w-full object-cover"
        autoPlay
        muted
        loop
        playsInline
        preload="metadata"
        aria-hidden="true"
      >
        <source src="/hero-video.mp4" type="video/mp4" />
      </video>

      <div className="relative z-10 mx-auto max-w-6xl px-6 py-24">
        <h1 className="text-5xl font-bold text-white">
          Build products people remember.
        </h1>
      </div>
    </section>
  );
}

Der entscheidende Teil hier ist überhaupt nicht die Video-Markup-Struktur.

Sondern diese eine Zeile:

min-height: 70svh;

Deshalb hat der Hero-Bereich bereits vor dem Start des Videos eine bekannte visuelle Präsenz.

Das Video selbst ist absolut innerhalb dieses Containers positioniert, was bedeutet, dass es keine Möglichkeit hat, den Inhalt darunter plötzlich zu verschieben, sobald seine Ressourcen geladen sind.

Dieser Unterschied verändert alles daran, wie stabil die Seite wirkt.

Lassen Sie das Video nicht Ihr Layout bestimmen

Eine typische, problematische Konfiguration sieht so aus:

<video
  src="/hero-video.mp4"
  autoPlay
  muted
  loop
/>

Dann kommt jemand mit Folgendem:

video {
  width: 100%;
}

Und wundert sich später, warum die Seite je nach Verbindungsqualität oder Bildschirmgröße unzuverlässig funktioniert.

Das Problem ist, dass der Browser die Abmessungen des Videos im Voraus kennen muss. Wenn ein Video rein dekorativer Hintergrundinhalt ist, gibt es selten einen guten Grund dafür, dass es überhaupt am normalen Dokumentfluss teilnimmt.

Anstatt dessen sollte die Verantwortung für die Anordnung dem umschließenden Container übertragen werden, also dem div, das das Video-Element umgibt.

<div style="height: 100px; width: 100%">
  <video
    src="/hero-video.mp4"
    autoPlay
    muted
    loop
  />
</div>

Mit dieser Struktur kann das Video intern nach Belieben funktionieren, doch das umgebende div hält alles in Schach.

Nutzen Sie object-fit: cover für Hintergrundvideos

Sobald das Video in einer absoluten Positionierung angeordnet ist, wird object-fit: cover tatsächlich nützlich – ein seltener Fall, in dem eine CSS-Eigenschaft genau so funktioniert, wie beabsichtigt.

.heroVideo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

Dadurch kann das Video den reservierten Hero-Bereich vollständig ausfüllen, ohne die Abmessungen des Containers selbst zu verändern.

Es gibt einen kleinen Kompromiss, den man beachten sollte: Der Wert cover schneidet Teile des Videos ab, wenn das Seitenverhältnis des Ansichtsfensters nicht mit dem des Quellmaterials übereinstimmt. Das ist ein akzeptabler Preis.

Der eigentliche Fehler besteht darin, die pixelgenaue Erhaltung des Originalvideos in den Vordergrund zu stellen, obwohl das Design eigentlich eine stabile, vorhersehbare Anordnung erfordert.

Nutzen Sie ein Poster als erstes visuelles Element

Eine besonders wirksame Technik ist es, ein sorgfältig ausgewähltes Poster-Bild für das Video-Element bereitzustellen.

<video
  className="absolute inset-0 h-full w-full object-cover"
  autoPlay
  muted
  loop
  playsInline
  preload="metadata"
  poster="/images/hero-poster.webp"
  aria-hidden="true"
>
  <source src="/videos/hero.mp4" type="video/mp4" />
</video>

Das Poster bietet den Besuchern etwas Konkretes zum Anschauen, während das eigentliche Video noch heruntergeladen wird. Wählen Sie dieses Bild sorgfältig aus, da es im Grunde Ihr Ersatzdesign darstellt.

Noch wichtiger ist, dass dadurch Ihre Anordnung nicht mehr davon abhängt, ob die Video-Ressource sofort verfügbar ist.

Betrachten Sie das Poster als zuverlässigen Grundzustand, wobei das Video selbst als progressive Verbesserung darauf gelegt wird – ähnlich wie ein Skeleton-Loader oder Spinner in anderen Kontexten funktioniert.

Falls das Video über eine langsame Mobilverbindung einige Sekunden braucht, um anzuzeigen, wirkt die Seite dennoch ordentlich und vollständig geladen und nicht beschädigt oder nur teilweise geladen.

Achtung vor den Fallstricken von 100vh

Videos im Vollbildmodus bergen eine weitere subtile Falle.

Zuvor schrieben Entwickler in der Regel:

height: 100vh;

Mobilbrowser erschweren dies, da die sichtbare Ansichtshöhe sich ändert, je nachdem, ob der Browserrahmen (Adressleiste, Werkzeugleisten) sichtbar oder unsichtbar ist, wodurch 100vh nicht so funktioniert, wie man es erwarten würde.

Für Layouts, die sich gut auf verschiedenen Geräten anpassen müssen, ist es in der Regel besser, neuere Ansichtseinheiten zu verwenden, wie zum Beispiel:

min-height: 100svh;

oder je nachdem, wie viel des Bildschirms das Hero-Element ausfüllen soll:

min-height: 80svh;

Kurz gesagt: Verwenden Sie lieber 100dvh oder 100svh anstelle des älteren 100vh.

Vermeiden Sie die Bereitstellung von Videos im Desktop-Format für Mobilnutzer

Auch eine Seite mit perfektem CLS kann noch immer extrem langsam wirken, wenn das Hintergrundvideo selbst sehr groß ist.

Dabei wird die Leistungsoptimierung noch anspruchsvoller.

Ein umfangreicher, filmischer Clip mit 12 MB Größe kann zwar über eine schnelle Desktop-Verbindung hervorragend abgespielt werden, doch auf einem Mobilgerät mit instabilem Netzwerk wird derselbe Datei eine echte Belastung.

Für die meisten Landingpages macht es Sinn, separate Video-Dateien für Desktop- und Mobilansichten bereitzustellen.

In einigen Fällen ist es angebracht, für bestimmte Besucher das Video ganz wegzulassen.

Die Berücksichtigung der Präferenz eines Nutzers für reduzierte Bewegungen ist ein gutes Beispiel dafür:

const prefersReducedMotion =
  window.matchMedia("(prefers-reduced-motion: reduce)").matches;

In einer echten React-Anwendung muss diese Überprüfung in einem Client-Komponenten stattfinden, und Sie sollten sie sorgfältig handhaben, damit sie die auf dem Server gerenderte HTML-Struktur nicht destabilisiert.

Die zugrundeliegende Regel ist einfach: Leistungs- und Barrierefreiheitsaspekte sollten bestimmen, ob das Video überhaupt abgespielt wird – und nicht nur, wie schnell es heruntergeladen wird.

Lassen Sie niemals das Video die Layout-Struktur bestimmen

Das ist das Leitprinzip, das man stets im Hinterkopf behalten sollte.

Ihre Seitenstruktur sollte auch bei dieser Abfolge funktionieren:

Hero container
    ↓
Poster
    ↓
Video enhancement

und niemals von diesem abhängen:

Video starts loading
    ↓
Browser discovers dimensions
    ↓
Hero changes height
    ↓
Everything below moves
    ↓
Lighthouse gets angry

Der Browser muss Ihre Layout-Struktur bereits verstehen, bevor das größere Medienmaterial angezeigt wird.

Das ist die eigentliche Lösung für CLS-Probleme, die durch Videos verursacht werden.

Um dies in der Praxis zu überprüfen, laden Sie Ihre Website über eine eingeschränkte, langsamere Netzwerkverbindung und beobachten Sie ihr Verhalten.

Verwandte Artikel

  • CSS-Custom-Eigenschaften zur Laufzeit: Theming, JS-Brücken und @property — Erfahren Sie, wie sich CSS-Custom-Eigenschaften von Sass-Variablen unterscheiden, und nutzen Sie sie für Theming, von JavaScript gesteuerte Effekte, fließende Schriftgrößen, Komponentenvarianten sowie typisierte Animationen.
  • Container Queries gegenüber Media Queries: Entscheidungen für Seiten und Komponenten — Lernen Sie, wann Sie sich auf Media Queries verlassen sollten und wann Container Queries besser geeignet sind, anhand von Beispielen mit Karten, Dashboards und Einheiten, die es wiederverwendbaren Komponenten ermöglichen, sich anzupassen.