4 Tricks, die uns geholfen haben, das Frontend zu optimieren

Schöne Animationen sind seit langem in Designtrends verankert. UI-Designer erstellen aufwendige Karussells, Downloads, Menüanimationen und andere Dekorationen, während Frontend-Entwickler sie in Code übersetzen. Die Seite sollte aber nicht nur gut aussehen, sondern auch schnell funktionieren.


Ein modernes Frontend sollte seinen Code optimieren. Dies gilt insbesondere für Produkte, bei denen der größte Teil des Publikums von mobilen Geräten auf die Website gelangt. Einige Animationsmethoden bleiben sogar in Chrome auf Top-Computern zurück, sollten jedoch auf einem durchschnittlichen Smartphone reibungslos funktionieren.


Unsere Entwickler verwendeten eine Vielzahl von Techniken, um die Website zu optimieren und ihre Arbeit zu beschleunigen. Ich habe 4 der interessantesten gesammelt. Wir teilen Wissen, das für Anfänger und Profis nützlich ist, und bieten Links zu nützlichen Tutorials.



1. Animation auf SCSS


Die Seite hat viele Animationen. Wir brauchen den Browser, um ihn mit einer stabilen Bildrate von 60 fps abzuspielen. In reinem CSS ist dies schwierig, daher verwenden wir SCSS.


Um die Schieberegler zu erstellen, haben wir die Swiper- Bibliothek verwendet. Für einen horizontalen Schieberegler ist die Verwendung dieser Bibliothek gerechtfertigt, da wir vom Benutzer Unterstützung für svayp bereitstellen mussten. Für ein vertikales Endloskarussell wird Swiper jedoch nicht benötigt, es gibt keine Benutzerinteraktion. Daher wollten wir dieselbe Funktionalität nur mit CSS-Funktionen wiederholen.


Die erste und wichtigste Bedingung beim Arbeiten mit CSS-Animationen ist die Verwendung nur der Transformations- und Deckkrafteigenschaften. Browser können die Animation dieser Eigenschaften unabhängig voneinander optimieren und stabile 60 fps erzeugen. Die Verwendung von @keyframes allein ist jedoch nicht möglich, um unterschiedliche Animationen für unterschiedliche Elemente zu schreiben, und es ist zu zeitaufwändig, jedes Element einzeln in reinem CSS zu animieren. Wie schreibe ich schnell die Animation, die wir brauchen? Wir haben uns für SCSS entschieden, den SASS-Dialekt - eine funktionalere CSS-Erweiterung.


Lassen Sie uns die Verwendung von SCSS am Beispiel unseres vertikalen Schiebereglers analysieren.



Zu unserer Verfügung steht ein Behälter, dessen Höhe der Höhe der drei Elemente des Karussells entspricht. Im Inneren befindet sich ein weiterer Behälter, der alle Elemente des Karussells enthält.


<div class="b-vertical-carousel-slider"> <div class="vertical-carousel-slider-wrapper slider-items"> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> </div> </div> 

Wir entfernen die Sichtbarkeit der darüber hinausgehenden Containerelemente und legen die Höhe der Blöcke fest.


 .b-vertical-carousel-slider { position: relative; overflow: hidden; height: $itemHeight * 3; .vertical-carousel-slider-item { height: $itemHeight; } } 

Die Berechnung der Animation ändert sich nur, wenn sich die Anzahl der Elemente im Karussell ändert. Als nächstes schreiben wir ein Mixin, das einen Eingabeparameter verwendet - $itemCount


 @mixin verticalSlideAnimation($itemCount) { } 

Generieren Sie im Mixin einen Keyframe für jedes Element, legen Sie den Anfangszustand dafür fest und bestimmen Sie mit :nth-child die Animation für das Element.


 for $i from * 1 through $itemCount { $animationName: carousel-item-#{$itemCount}-#{$i}; @keyframes #{$animationName} { 0% { transform: translate3d(0, 0, 0) scale(.95); } } .vertical-carousel-slider-item:nchild(#{$i}) { animation: $stepDuration * $itemCount $animation ease infinite; } } 

Während der Animation verschieben wir die Elemente nur entlang der y-Achse und ändern die Skalierung für das Element in der Mitte.


Karussellelementzustände:


  1. Frieden
  2. Y-Offset
  3. Y-Offset
  4. Y-Versatz mit abnehmendem

Jeder Gegenstand bewegt sich um $itemCount Zeiten nach oben, erhöht sich einmal und verringert sich einmal während der Bewegung. Daher werden wir die Animation für jede der Aufwärtsbewegungen generieren und berechnen.


 @keyframes #{$animationName} { 0% { transform: translate3d(0, 0, 0) scale(.95); } @for $j from 0 through $itemCount { $isFocusedStep: $i == $j + 2; $isNotPrevStep: $i != $j + 1; $offset: 100% / $itemCount * ($animationTime / $stepDuration); @if ($isFocusedStep) { #{getPercentForStep($j, $itemCount, $offset)} { transform: getTranslate($j - 1) scale(.95); } #{getPercentForStep($j, $itemCount)} { transform: getTranslate($j) scale(1); } #{getPercentForStep($j + 1, $itemCount, $offset)} { transform: getTranslate($j) scale(1); } #{getPercentForStep($j + 1, $itemCount)} { transform: getTranslate($j + 1) scale(.95); } } @else if ($isNotPrevStep) { #{getPercentForStep($j, $itemCount, $offset)} { transform: getTranslate($j - 1) scale(.95); } #{getPercentForStep($j, $itemCount)} { transform: getTranslate($j) scale(.95); } } } } 

Es bleiben noch einige Variablen und Funktionen zu definieren:


  • $animationTime - Bewegungszwischenzeit
  • $stepDuration - Gesamtausführungszeit eines Animationsschritts ( $animationTime + Karussellruhezeit)
  • getPercentForStep($step, $itemCount, $offset) - eine Funktion, die den Extrempunkt eines der Zustände in Prozent zurückgibt.
  • getTranslate($step) - gibt je nach Animationsschritt die Übersetzung zurück

Beispiel für Funktionsimplementierungen:


 @function getPercentForStep($step, $count, $offset: 0) { @return 100% * $step / $count - $offset; } @function getTranslate($step) { @return translate3d(0, -100% * $step, 0); } 

Wir haben ein funktionierendes Karussell mit einem zunehmenden Element in der Mitte. Es bleibt ein Schatten unter den zunehmenden Elementen zu machen. Anfangs hatte jedes Element des Karussells ein Pseudoelement: danach, das wiederum einen Schatten hatte. Um die Schatteneigenschaft nicht zu animieren, haben wir die Opazitätseigenschaft dafür verwendet, d.h. zeigte nur und versteckte den Schatten.


In der neuen Implementierung für eine solche Lösung müssen Sie jedoch viele zusätzliche Keyframes für jedes Pseudoelement generieren. Wir haben beschlossen, es einfacher zu machen: Es wird einen Block mit einem Schatten geben, der genau unter dem mittleren Element des Karussells Platz einnimmt.


Fügen Sie ein Div hinzu, das für den Schatten verantwortlich ist.


 <div class="b-vertical-carousel-slider"> <div class="vertical-carousel-slider-wrapper"> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> <div class="vertical-carousel-slider-item"></div> </div> <div class="vertical-carousel-slider-shadow"></div> </div> 

Wir stilisieren es und fügen Animationen hinzu.


 @keyframes shadowAnimation { 0% { opacity: 1; } 80% { opacity: 1; } 90% { opacity: 0; } 100% { opacity: 1; } } .vertical-carousel-slider-shadow { top: $itemHeight; left: 0; right: 0; height: $itemHeight; animation: $stepDuration shadowAnimation ease infinite; } 

In diesem Fall müssen Sie keine Möglichkeit zum Animieren des Schattens unter jedem Element generieren und überlegen, wir animieren nur einen Block, er hat zwei Zustände - er ist sichtbar und verborgen


Als Ergebnis haben wir ein reines CSS-Karussell, das nur mit gut optimierten Eigenschaften animiert. Dadurch kann der Browser die Hardwarebeschleunigung zum Rendern verwenden. Daher der greifbare Gewinn im Vergleich zu JS Animation:


  1. Beim Scrollen von Seiten mit Animationen auf schwachen Geräten wurden Frames in JS-Animationen deutlich übersprungen, wodurch die FPS auf 15 bis 20 gesenkt wurden. CSS-Animationen haben die Dinge deutlich verbessert. Auf diesen Geräten betrug diese Zahl mindestens 50-55 FPS.
  2. Wir haben die Arbeit eines Drittanbieter-Moduls losgeworden, für das es nicht erforderlich war.
  3. Die Animation wird auch dann abgespielt, wenn JS deaktiviert ist

JS-Animationen sollten verwendet werden, wenn eine strikte Kontrolle über jedes Bild erforderlich ist: Pause, Rückwärtswiedergabe, Rücklauf, Reaktion auf Benutzeraktionen. In anderen Fällen empfehlen wir die Verwendung von reinem CSS.


Nützliche Links



2. Verwenden der Intersection Observer-API


Die Animation, die der Site-Besucher nicht sieht, wird irgendwo außerhalb der Sichtweite abgespielt und lädt die CPU. Mit dem Intersection Observer bestimmen wir, welche Art von Animation gerade auf dem Bildschirm sichtbar ist, und spielen sie nur ab.


Alle Tricks aus dem letzten Absatz können mit dem Intersection Observer kombiniert werden. Dieses Tool hilft, den Browser nicht mit Animationen zu laden, die der Site-Besucher nicht sieht. Bisher wurden ressourcenintensive „Zuhörer“ von Ereignissen verwendet, um zu verstehen, ob ein Besucher ein animiertes Element betrachtete, und dies erzeugte keinen starken „Auspuff“. Der Unterschied zwischen der Verwendung von Animationen außerhalb des Ansichtsfensters und der Verwendung von Listenern war minimal. Die Intersection Observer-API benötigt weniger Ressourcen und hilft dabei, nur die Animation abzuspielen, die für den Besucher sichtbar ist.


Auf unserer Website wird die Animation nur aktiviert, wenn ein Element im Ansichtsfenster angezeigt wird. Wenn wir dies nicht tun würden, würden die Seiten mit der ständigen Ausführung von Schleifenanimationen überladen, die nicht sichtbar waren. Mit der Intersection Observer-API können Sie den Schnittpunkt des Elements mit dem übergeordneten Element oder den Umfang des Dokuments überwachen.


Implementierungsbeispiel


Als Beispiel zeigen wir, wie Sie die Animation in JS optimieren können. Die Idee ist einfach: Die Animation wird abgespielt, während sich das animierte Element im Ansichtsfenster befindet. Für die Implementierung verwenden wir die Intersection Observer API.


Fügen Sie den Stilen eine is-paused Klassenbehandlung hinzu


 .b-vertical-carousel-slider.is-paused { .vertical-carousel-slider-wrapper { .vertical-carousel-slider-item { animation-play-state: paused; } } .vertical-carousel-slider-shadow { animation-play-state: paused; } } 

Das heißt, Wenn diese Klasse angezeigt wird, wird die Animation angehalten.


Nun beschreiben wir die Logik des Hinzufügens und Entfernens dieser Klasse


 if (window.IntersectionObserver) { const el = document.querySelector('.b-vertical-carousel-slider'); const observer = new IntersectionObserver(intersectionObserverCallback); observer.observe(el); } 

Hier haben wir eine Instanz von IntersectionObserver erstellt und die Funktion intersectionObserverCallback angegeben, die funktioniert, wenn sich die Sichtbarkeit ändert.


Definieren Sie nun intersectionObserverCallback


 function intersectionObserverCallback(entries){ if (entries[0].intersectionRatio === undefined) { return; } helperDOM.toggleClass(el, 'is-paused', entries[0].intersectionRatio <= 0); }; 

Jetzt wird die Animation nur auf den sichtbaren Elementen abgespielt. Sobald das Element aus dem Sichtfeld verschwunden ist, wird die Animation angehalten. Wenn der Besucher zu ihm zurückkehrt, wird die Wiedergabe fortgesetzt.


Nützliche Links



3. SVG-Rendering


Eine große Anzahl von Bildern oder die Verwendung von Sprites führt in den ersten Sekunden nach dem Laden zu Friesen und Verzögerungen. Durch das Einbetten von SVG in den Seitencode wird das Laden visuell reibungsloser.


Bei der Auswahl der Methoden für die Arbeit mit Bildern hatten wir zwei Optimierungsoptionen: Einbetten von SVG in HTML oder Verwenden von Sprites. Wir haben uns für die Einbettung entschieden. Wir binden den XML-Code jedes Bildes direkt in den HTML-Code der Seiten ein. Dadurch wird die Größe geringfügig erhöht, SVG wird jedoch sofort im Dokument bereitgestellt.


Viele Entwickler verwenden weiterhin SVG-Sprites. Was ist das Wesentliche der Methode: Eine Reihe von Bildern (z. B. Symbole) werden in einer großen Bildfläche gesammelt, die als Sprite bezeichnet wird. Wenn Sie ein bestimmtes Symbol anzeigen müssen, wird ein Sprite aufgerufen, nach dem die Koordinaten des bestimmten Teils angegeben werden, auf dem es sich befindet. Dies ist schon lange geschehen, selbst bei der ersten Version von HTTP. Sprites halfen dabei, die Datei aggressiv zwischenzuspeichern und die Anzahl der Serveranforderungen zu reduzieren. Dies war wichtig, da viele gleichzeitige Anforderungen den Browser verlangsamten. Die Verwendung von SVG-Sprites ist eine typische Krücke, mit der Sie die Logik des Arbeitens vernachlässigen, um Ressourcen zu sparen. Jetzt ist die Anzahl der Anfragen nicht mehr so ​​wichtig, daher empfehlen wir das Einbetten.


Erstens wirkt es sich positiv auf die Leistung aus Sicht des Besuchers aus. Er sieht, wie die Symbole sofort geladen werden und leidet nicht die ersten Sekunden nach dem Laden der Seite. Bei Verwendung von Sprite- oder PNG-Bildern wird die geladene Seite etwas langsamer. Dies ist besonders dann zu spüren, wenn der Besucher die geladene Seite sofort scrollt - FPS sinkt auf Nicht-Top-Geräten auf 5-15. Durch das Einbetten von SVG in HTML wird die Seitenlatenz verringert (subjektiv aus Sicht des Clients) und Friese und Framesprünge beim Laden werden entfernt.


4. Caching mit Service Worker und HTTP-Cache


Es macht keinen Sinn, eine nicht geänderte Seite neu zu laden und den Besucherverkehr zu verwenden. Es gibt viele Caching-Strategien, wir haben uns für die effizienteste Kombination entschieden.


Es lohnt sich, nicht nur die CPU / GPU, sondern auch das Netzwerk optimal zu nutzen. Mobile Geräte sind nicht nur in Bezug auf Ressourcen, sondern auch in Bezug auf Internetgeschwindigkeit und Datenverkehr eine Einschränkung. Caching hat uns hier geholfen. Sie können Antworten auf HTTP-Anforderungen speichern und verwenden, ohne erneut eine Antwort vom Server zu erhalten.


Als wir über eine Caching-Strategie nachdachten, entschieden wir uns, Service Worker und HTTP-Cache gleichzeitig zu verwenden. Beginnen wir mit dem ersten und fortgeschritteneren. Service Worker ist eine js-Datei, die ihre Seite oder Datei steuern, Anforderungen abfangen und ändern sowie Anforderungen programmgesteuert zwischenspeichern kann. Es fungiert als Proxy zwischen der Site und dem Server und bestimmt deren Offline-Verhalten. All dies geschieht auf der "Vorderseite", ohne ein "Backend" anzuschließen.


Service Worker hat eine enorme Variabilität. Wir können das Verhalten nach Belieben programmieren. Wir wissen beispielsweise, dass ein Besucher, der mit einer Wahrscheinlichkeit von 90% auf Seite 1 gegangen ist, auf Seite 2 geht. Wir bitten SW, die zweite Seite mit dem Hintergrund zu laden, wenn sich der Besucher noch auf der ersten befindet. Wenn er dazu geht, wird die Seite sofort geladen. Es kann für verschiedene Aufgaben verwendet werden:


  • Hintergrunddatensynchronisation
  • Offline-Rechner
  • Benutzerdefinierte Vorlagen
  • Reaktion auf eine bestimmte Zeit und ein bestimmtes Datum.

Service Worker-Dateien können in verschiedenen Diensten erstellt werden. Wir empfehlen Workbox . Es ist recht einfach und ermöglicht es Ihnen, eine Reihe von Regeln zu erstellen, nach denen das Caching ausgeführt wird, z. B. Precache.


Servicemitarbeiter unterstützen nicht alle Browser wie IE, Safari oder Chrome vor Version 40.0. Wenn das Gerät nicht damit arbeiten kann, befolgt es die HTTP-Cache-Caching-Regeln. Wir haben den Seiten die folgenden HTTP-Header hinzugefügt:


 cache-control: no-cache last-modified: Mon, 06 May 2019 04:26:29 GMT 

In diesem Fall fügt der Browser dem Repository Antworten auf Anforderungen hinzu, sendet jedoch bei jeder nachfolgenden Anforderung einen Header, um nach Änderungen zu suchen.


 if-modified-since: Mon, 06 May 2019 04:26:29 GMT 

Falls keine Änderungen aufgetreten sind, erhält der Browser eine Antwort mit dem Code 304 Nicht geändert und verwendet den im Cache gespeicherten Inhalt. Wenn Änderungen am Dokument vorgenommen werden, wird die Antwort mit dem Code 200 zurückgegeben und eine neue Antwort in den Browserspeicher geschrieben.


Wenig später haben wir die Caching-Methode geändert und die Hash-Menge im Dateinamen überprüft. Es stellt sicher, dass die Ressource eindeutig bleibt. Daher könnten wir Inhalte aggressiv zwischenspeichern. Der folgende Header wurde als Antwort hinzugefügt:


 Cache-control:max-age=31536000, immutable 

Das maximale Alter gibt die maximale Caching-Zeit an, in unserem Fall 1 Jahr. Ein unveränderlicher Wert bedeutet, dass eine solche Antwort nicht auf Änderungen überprüft werden muss.


Nützliche Links



Dies sind nicht alle Möglichkeiten, um die Site zu optimieren. Dies könnte zu einer Ablehnung des Bootstraps führen, die Anzahl der DOM-Elemente und -Ereignisse verringern und vieles mehr. Dies sind jedoch die Tipps, die uns geholfen haben, die Website trotz der großen Menge an Animationen schnell und reaktionsschnell zu gestalten.


Wir laden Sie in unser Team ein


Für unsere ehrgeizigen Aufgaben suchen wir in unserem Büro in St. Petersburg immer coole Spezialisten: Entwickler, Tester, Designer. Unten gibt es offene Stellen - machen Sie mit.


Source: https://habr.com/ru/post/de455700/


All Articles