Insight · ·

Zwei laufende Videos halbierten unsere Frame Rate. Die Videos waren nicht das Problem

Ein bewegtes Parent machte das zweite Video teuer. Ein sichtbarkeitsgesteuerter Playback Slot beseitigte alle Frames über 33ms, ohne die Clips zu ändern.

Zwei laufende Videos halbierten unsere Frame Rate. Die Videos waren nicht das Problem

Ein laufender Clip hielt einen Median Frame von 16.7ms. Mit einem zweiten Clip fiel dieselbe Szene auf 33.3ms, und 97 Prozent der Frames kamen zu spät. Sonst hatte sich auf der Seite nichts geändert.

Diese Messungen stammen aus unserer Arbeit an clodron.com im August 2026. Der Test lief auf einem gepinnten horizontalen Track, der sichtbar auf der X Achse verschoben wurde, mit 6x CPU Throttling und 2x Device Pixel Ratio. Der offensichtliche Verdacht war Video Decoding. Er war falsch.

Der Trace schloss JavaScript aus

Sowohl der Lauf mit einem als auch mit zwei Videos enthielt null Long Tasks. Der Main Thread war weder durch Event Handler noch Animation Loop oder React Arbeit blockiert. Code aus dem Scroll Callback zu entfernen konnte keine Zeit zurückholen, die dort nicht verbraucht wurde.

Der entscheidende Kontrolltest war einfacher. Wir stoppten den horizontalen Track an derselben Scrollposition und liessen drei Clips laufen. Sie erzeugten keine messbaren Kosten. Dieselben Medien, derselbe Viewport und dieselbe Decoderlast verhielten sich normal, solange der umgebende Layer stillstand. Bewegung änderte die Kosten.

Damit wanderte die Untersuchung von den Dateien zur Composition. Ein Performance Trace ist wertvoll, wenn er eine plausible Geschichte ausschliesst, nicht nur eine bestätigt.

Ein transformierter Layer verändert den Videopfad

Die Section pinnte einen breiten Track und verschob ihn beim Scrollen auf der X Achse. Video kann normalerweise einen günstigen Compositor Pfad nutzen. Wird der umgebende Layer ständig transformiert, steht dieser Weg womöglich nicht mehr zur Verfügung. Jeder weitere laufende Clip bringt dann teure Composition Arbeit in jeden bewegten Frame.

Der Unterschied war nicht sichtbares gegen verstecktes Video. Es war laufendes Video innerhalb eines sich ändernden Layers. Deshalb waren mehrere stationäre Clips günstig und der zweite bewegte Clip unter Druck katastrophal.

Aus demselben Grund änderte weniger JavaScript nichts. Die späten Frames entstanden nach der Main-Thread Arbeit, die Entwickler meist zuerst untersuchen.

Zwei vernünftige Fixes änderten nichts

Wir entfernten einen will-change Hint. Das Ergebnis blieb gleich. Wir ergänzten contain: paint. Auch das änderte nichts. Beide Versuche waren sinnvoll, weil Layer Promotion und Paint Containment bewegte Sections beeinflussen können. Den tatsächlichen Videopfad dieser Szene trafen sie nicht.

Das ist der unbequeme Teil von Browser Performance. Eine bekannte Optimierung kann Architektur verbessern und trotzdem keinen messbaren Nutzen im fehlerhaften Trace erzeugen. Ohne bewegte Vorher-Nachher Messung gehört sie nicht als Lösung in die Erklärung.

Auch kleinere Encodes waren nicht der Anfang. Dateigrösse zählt für Transfer und Startup. Sie erklärte nicht, warum dieselben decodierten Clips bei stillstehendem Track kostenlos wurden.

Playback gehört dem Viewport

Die Lösung war ein einzelner Playback Slot. Während der bewegten Section durfte nur die am stärksten sichtbare Card spielen. Der vorherige Clip pausierte, bevor der nächste begann. Cards blieben mit Poster Frames visuell vollständig, der Compositor trug aber nur ein aktives Video durch die Transformation.

Diese Policy brachte die gesamte Seite von 13.8 Prozent der Frames über 33ms auf null. Sie machte auch das Performance Modell ausdrücklich. Playback war keine zufällige Eigenschaft jeder Card mehr, sondern eine Ressource des Viewports.

Die Auswahl braucht Hysterese, damit zwei ähnlich sichtbare Cards den Slot nicht ständig tauschen. Playback State reagiert ausserdem auf Tab Visibility und Reduced Motion.

Diese Woche den bewegten Layer diagnostizieren

Wenn zusätzliche Videos den Scroll beschädigen, kommt der stationäre Kontrolltest vor jedem neuen Encode. Dieselbe Scrollposition bleibt stehen, die Clips laufen weiter und Frame Timing wird verglichen. Long Tasks werden separat geprüft, damit Main Thread und Compositor nicht vermischt werden.

Danach spielt nur der sichtbarste Clip, während sich der transformierte Layer bewegt. Gemessen wird die komplette Seite, nicht nur die isolierte Section. Fehlgeschlagene Experimente bleiben in der Performance Notiz. Dass will-change und contain: paint nichts änderten, schützt den nächsten Engineer vor derselben plausiblen, aber irrelevanten Reparatur.

Die Videos waren einzeln nicht zu schwer. Die Seite hatte den Compositor gebeten, mehrere aktive Videoflächen gleichzeitig zu bewegen. Die dauerhafte Lösung begrenzte diesen knappen Pfad, statt weiter an unabhängigem Code zu schleifen.