| Zusammenfassung | Discourse-Plugin, das die Anpassung des Splash-Screens mithilfe von vom Administrator definierten HTML- und CSS-Codes ermöglicht. | |
| Repository-Link | https://github.com/VaperinaDEV/custom-splash-html-builder | |
| Gefällt es dir? | > ./support --coffee | |
| Installationsanleitung | So installierst du Plugins in Discourse |
Hallo ![]()
Ich habe ein kleines Discourse-Plugin erstellt, mit dem der Splash-Screen mithilfe von vom Administrator definierten HTML- und CSS-Codes angepasst werden kann, ohne dass eine modifizierte Kopie der zentralen Splash-Vorlage von Discourse gepflegt werden muss.
Die ursprüngliche Motivation für die Erstellung dieses Plugins war tatsächlich die Mobile Performance.
Ich wollte einen ausgefeilteren animierten Splash-Screen erstellen, stellte jedoch fest, dass die SVG-Animationen, die von der aktuellen zentralen Splash-Implementierung von Discourse unterstützt werden, auf mobilen Geräten überraschende Probleme verursachen können.
Auf dem Desktop kann die Animation völlig flüssig aussehen, während sie auf Mobilgeräten deutlich ruckeln, Frames verlieren, verzögert ablaufen oder sogar während der Animation stehen bleiben kann.
Nachdem ich verschiedene Ansätze ausprobiert hatte, stellte ich fest, dass das Verschieben der Animation vom SVG selbst auf ein umgebendes HTML-Element, wie z. B. ein <div>, einen sehr großen Unterschied machte.
Anstatt die SVG-Inhalte kontinuierlich zu animieren, kann das SVG statisch bleiben, während der Browser die umgebende HTML-Ebene mit CSS-Transforms animiert.
So hat der Browser eine viel bessere Möglichkeit, die Animation als Kompositing-Operation mit der Grafikhardware des Geräts zu verarbeiten.
Das Ergebnis war eine deutlich flüssigere Animation auf Mobilgeräten, ohne die Ruckler und Einfrieren, die ich bei dem SVG-basierten Ansatz beobachtet hatte.
Das war der Hauptgrund für die Erstellung dieses Plugins.
Vorher (Animiertes SVG: Die Animation ruckelt und bleibt stehen)
Nachher (Animiertes HTML: Fließende Animation)
Das Problem mit der Animation von SVGs
Die ursprüngliche Splash-Implementierung ist für ein einfaches Logo oder eine relativ leichte Animation völlig in Ordnung.
Sobald die Animation jedoch komplexer wird, kann die SVG-Darstellung aufwendig werden.
Zum Beispiel kann eine Animation, die direkt auf ein SVG oder seine internen Elemente angewendet wird, dazu führen, dass der Browser während der Animation Teile des SVGs wiederholt verarbeiten oder neu zeichnen muss.
Auf mobilen Geräten kann dies besonders deutlich spürbar sein.
Während der Tests sah ich Fälle, in denen die Animation:
- sichtbar ruckelte
- vorübergehend einfroren
- stehen blieb
- sich deutlich schlechter verhielt als auf dem Desktop
Der interessante Teil war, dass sich dieselbe visuelle Animation je nachdem, was tatsächlich animiert wurde, sehr unterschiedlich verhalten konnte.
Die Animation auf eine HTML-Ebene verschieben
Der Ansatz, der viel besser funktionierte, bestand darin, das SVG selbst statisch zu lassen und es in ein normales HTML-Element zu setzen.
Zum Beispiel:
<div class="logo-layer">
<svg viewBox="0 0 500 500">
...
</svg>
</div>
Anstatt das SVG zu animieren, wird die Animation auf den Container angewendet:
#d-splash .logo-layer {
animation: pulse 1.8s ease-in-out infinite;
will-change: transform;
}
@keyframes pulse {
0%,
100% {
transform: scale(0.8);
}
50% {
transform: scale(0.85);
}
}
Das SVG selbst ändert sich nicht.
Der Browser kann die Transformation der HTML-Ebene daher viel effizienter verarbeiten und sie in unterstützten Fällen zu einer kompositierten Ebene hochstufen, die von der Grafikhardware bearbeitet wird.
Dies führte zu einem dramatisch flüssigeren Ergebnis auf mobilen Geräten.
Der wichtige Unterschied ist daher:
Zentraler Ansatz:
SVG
└── SVG-Animation
└── SVG-Inhalte werden animiert
vs.:
Eigener Ansatz:
HTML-Ebene
└── SVG
└── CSS-Transform auf der HTML-Ebene
└── Für den Kompositor geeignete Animation
Das ist keine Garantie dafür, dass jede Animation GPU-beschleunigt wird. Der Browser entscheidet letztendlich, wie eine Animation kompositiert wird, aber in meinen Tests war der Unterschied sehr deutlich.
Warum ich den Custom Splash HTML Builder erstellt habe
Sobald dieser Ansatz funktionierte, brauchte ich auch eine Möglichkeit, den Splash-Screen darum herum zu gestalten.
Die Standard-Splash-Vorlage bietet für diese Art von Implementierung nicht genügend Flexibilität.
Für eine komplexere Animation könnte ich Folgendes benötigen:
- mehrere SVG-Ebenen
- mehrere HTML-Container
- unabhängig animierte Elemente
- benutzerdefinierte CSS-Keyframes
- unterschiedliche Animationszeiten
- benutzerdefinierte Positionierung
- eine völlig andere Markup-Struktur als die Standard-Splash-Vorlage
Also entschied ich mich, anstatt einer weiteren hartkodierten Splash-Implementierung, den visuellen Teil über zwei Seiteneinstellungen bereitzustellen.
Das Plugin fügt hinzu:
splash_custom_html
Das HTML/SVG-Markup, das innerhalb des Splash-Screens gerendert wird.
splash_custom_css
Das CSS, das vom benutzerdefinierten Splash verwendet wird, einschließlich Animationen, Keyframes, Positionierung und reaktivem Verhalten.
Dadurch ist der Splash-Screen effektiv anpassbar, ohne dass der Plugin-Quellcode jedes Mal geändert werden muss, wenn sich die Animation ändert.
Eingebauter Admin-Editor
Das Plugin bietet auch einen kleinen eingebauten Admin-Editor zum Verwalten des benutzerdefinierten Splash-Screens.
Er fügt eine dedizierte Splash HTML Builder-Sektion in der Discourse-Admin-Oberfläche hinzu, mit separaten Editoren für:
- Benutzerdefiniertes HTML
- Benutzerdefiniertes CSS
Die Änderungen können direkt aus der Admin-Oberfläche gespeichert werden, ohne die entsprechenden Seiteneinstellungen manuell bearbeiten zu müssen.
Die zugrunde liegenden Einstellungen sind nach wie vor:
splash_custom_htmlsplash_custom_css
Der Editor ist einfach eine bequemere Oberfläche zum Verwalten dieser Einstellungen.
Das bedeutet auch, dass das Plugin keine Änderungen an den Plugin-Quelldateien erfordert, wann immer die Splash-Animation geändert werden muss.
Beispiel
Ein benutzerdefinierter Splash-Screen kann mehrere unabhängige Ebenen enthalten:
<div class="ring-layer">
<svg viewBox="0 0 500 500">
...
</svg>
</div>
<div class="logo-layer">
<svg viewBox="0 0 500 500">
...
</svg>
</div>
Und jede Ebene kann ihre eigene Animation haben:
#d-splash .ring-layer {
animation: rotate 2.2s linear infinite;
will-change: transform;
}
#d-splash .logo-layer {
animation: pulse 1.8s ease-in-out infinite;
will-change: transform;
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes pulse {
0%,
100% {
transform: scale(0.8);
}
50% {
transform: scale(0.85);
}
}
Die SVGs bleiben statisch, während die umgebenden HTML-Ebenen animiert werden.
So ist es möglich, deutlich komplexere Splash-Animationen zu erstellen, während die aufwendigen Animationsarbeiten außerhalb des SVGs selbst bleiben.
Warum nicht einfach die zentrale Splash-Vorlage überschreiben?
Ein weiteres wichtiges Ziel war es, die Pflege einer Kopie der zentralen Splash-Vorlage von Discourse zu vermeiden.
Ein naheliegender Ansatz wäre es, Folgendes zu überschreiben:
app/views/common/_discourse_splash.html.erb
und die aktuelle Discourse-Implementierung in das Plugin zu kopieren.
Das Problem ist, dass dies einen Wartungsaufwand mit sich bringt.
Wenn Discourse seine Splash-Implementierung in einer zukünftigen Version ändert, würde das Plugin immer noch die alte Version enthalten.
Das könnte potenziell zu Folgendem führen:
- verpasste neue zentrale Änderungen
- verpasste Performance-Verbesserungen
- fehlerhaftes Verhalten nach einem Discourse-Update
- manuelles Vergleichen der Plugin-Vorlage mit der zentralen Version nach jedem Update
Ich wollte das vollständig vermeiden.
Fallback auf die zentrale Implementierung
Das Plugin unterstützt daher einen benutzerdefinierten Splash mit Fallback auf die zentrale Implementierung.
Benutzerdefiniertes HTML ist konfiguriert
Wenn:
SiteSetting.splash_custom_html.present?
dann rendert das Plugin den benutzerdefinierten Splash.
Benutzerdefiniertes HTML ist leer
Wenn kein benutzerdefinierter Splash konfiguriert wurde, fällt das Plugin auf die aktuelle zentrale Splash-Vorlage von Discourse zurück.
Das Plugin lokalisiert die eigentliche zentrale Datei aus der laufenden Discourse-Installation:
Rails.root/app/views/common/_discourse_splash.html.erb
und rendert diese Implementierung.
Konzeptionell:
core_splash_path = Rails.root.join("app", "views", "common", "_discourse_splash.html.erb")
if File.exist?(core_splash_path)
render inline: File.read(core_splash_path), type: :erb
end
Das bedeutet, dass das Plugin keine zweite Kopie der zentralen Splash-Vorlage mitführt.
Performance-Überlegungen
Das Plugin behauptet nicht, dass jede CSS-Animation magisch GPU-beschleunigt wird.
Der Browser entscheidet immer noch, wie einzelne Animationen gerendert und kompositiert werden.
Das Ziel besteht stattdessen darin, dem Browser eine viel günstigere Struktur für hardwarebeschleunigtes Kompositing zu bieten:
- SVG-Inhalte statisch halten
- unabhängig animierte Elemente isolieren
- HTML-Ebenen animieren
transformfür Bewegung/Vergrößerung/Rotation bevorzugen- unnötig aufwendige Neuzeichnungsoperationen vermeiden
will-changebei Bedarf verwenden
Zum Beispiel:
#d-splash .ring-layer {
will-change: transform;
animation: rotate 2.2s linear infinite;
}
Dieser Ansatz funktionierte in meinem Anwendungsfall besonders gut und beseitigte das mobile Ruckeln, das ich bei der ursprünglichen SVG-Animation beobachtet hatte.
Den benutzerdefinierten Splash aktivieren oder deaktivieren
Das Plugin bietet auch eine Seiteneinstellung custom_splash_html_builder_enabled.
Wenn deaktiviert, wird der Standard-Splash-Screen von Discourse verwendet, unabhängig davon, ob benutzerdefiniertes HTML oder CSS konfiguriert wurde.
Dies bietet einen zusätzlichen Sicherheitsschalter, um den benutzerdefinierten Splash temporär zu deaktivieren, ohne das gespeicherte HTML/CSS zu löschen.
Der benutzerdefinierte Splash wird nur gerendert, wenn beide Bedingungen erfüllt sind:
custom_splash_html_builder_enabled = true
splash_custom_html ist nicht leer
Andernfalls wird die aktuelle zentrale Splash-Implementierung von Discourse verwendet.
Am wichtigsten ist, dass es eine Möglichkeit bietet, einen benutzerdefinierten animierten Splash zu erstellen, der auf Mobilgeräten viel besser funktioniert, indem er HTML-Ebenen um statische SVG-Inhalte herum animiert, anstatt das SVG selbst direkt zu animieren.