| Описание | Плагин для Discourse, позволяющий настраивать экран загрузки (splash screen) с использованием HTML и CSS, определенных администратором. | |
| Ссылка на репозиторий | https://github.com/VaperinaDEV/custom-splash-html-builder | |
| Нашли полезным? | > ./support --coffee | |
| Руководство по установке | Как установить плагины в Discourse |
Привет ![]()
Я создал небольшой плагин для Discourse, который позволяет настраивать экран загрузки с помощью HTML и CSS, определенных администратором, без необходимости поддерживать модифицированную копию основного шаблона экрана загрузки Discourse.
Первоначальной мотивацией для создания этого плагина была, на самом деле, производительность на мобильных устройствах.
Я хотел создать более изощренный анимированный экран загрузки, но обнаружил, что анимации SVG, поддерживаемые текущей основной реализацией экрана загрузки Discourse, могут вызывать неожиданные проблемы на мобильных устройствах.
На десктопе анимация могла выглядеть абсолютно плавной, в то время как на мобильных устройствах она могла заметно дёргаться, терять кадры, тормозить или даже казаться остановившейся во время воспроизведения.
После экспериментов с различными подходами я обнаружил, что перенос анимации из самого SVG на окружающий HTML-элемент, например <div>, дает очень значительную разницу.
Вместо непрерывной анимации содержимого SVG, SVG может оставаться статичным, в то время как браузер анимирует содержащий HTML-слой с помощью CSS-трансформаций.
Это дает браузеру гораздо больше возможностей для обработки анимации как операции композитинга с использованием графического оборудования устройства.
Результатом стала гораздо более плавная анимация на мобильных устройствах, без заиканий и зависаний, которые я наблюдал при использовании подхода на основе SVG.
Это была основная причина создания этого плагина.
До (Анимированный SVG: Анимация тормозит и останавливается)
После (Анимированный HTML: Плавная анимация)
Проблема с анимацией SVG
Оригинальная реализация экрана загрузки вполне подходит для простого логотипа или относительно легкой анимации.
Однако, когда анимация становится более сложной, рендеринг SVG может стать затратным.
Например, анимация, примененная непосредственно к SVG или его внутренним элементам, может потребовать от браузера многократной обработки или перерисовки частей SVG во время анимации.
На мобильных устройствах это может стать особенно заметным.
Во время тестирования я видел случаи, когда анимация:
- становилась заметно рваной
- временно зависала
- казалась остановившейся
- работала значительно хуже, чем на десктопе
Интересная часть заключалась в том, что одна и та же визуальная анимация могла вести себя очень по-разному в зависимости от того, что именно анимировалось.
Перенос анимации на HTML-слой
Подход, который сработал гораздо лучше, заключался в том, чтобы оставить сам SVG статичным и поместить его внутрь обычного HTML-элемента.
Например:
<div class="logo-layer">
<svg viewBox="0 0 500 500">
...
</svg>
</div>
Вместо анимации SVG, анимация применяется к контейнеру:
#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);
}
}
Сам SVG не меняется.
Таким образом, браузер может гораздо эффективнее обрабатывать трансформацию HTML-слоя и, в поддерживаемых случаях, выносить ее на отдельный слой композитинга, обрабатываемый графическим оборудованием.
Это дало значительно более плавный результат на мобильных устройствах.
Важное различие состоит в следующем:
Основной подход:
SVG
└── Анимация SVG
└── Анимация содержимого SVG
против:
Пользовательский подход:
HTML-слой
└── SVG
└── CSS-трансформация на HTML-слое
└── Анимация, удобная для композитинга
Это не гарантия того, что каждая анимация будет ускоряться GPU. В конечном итоге браузер решает, как композитировать анимацию, но в моих тестах разница была очень заметной.
Почему я создал Custom Splash HTML Builder
Когда этот подход начал работать, мне также потребовался способ фактически построить экран загрузки вокруг него.
Стандартный шаблон экрана загрузки не предоставляет достаточной гибкости для такого типа реализации.
Для более сложной анимации мне могло потребоваться:
- несколько слоев SVG
- несколько HTML-контейнеров
- независимо анимируемые элементы
- пользовательские CSS-кадровые анимации (keyframes)
- разные тайминги анимации
- пользовательское позиционирование
- разметка, полностью отличная от стандартного экрана загрузки
Поэтому, вместо создания еще одной жестко закодированной реализации экрана загрузки, я решил вынести визуальную часть через два параметра сайта.
Плагин добавляет:
splash_custom_html
Разметка HTML/SVG, отображаемая внутри экрана загрузки.
splash_custom_css
CSS, используемый для пользовательского экрана загрузки, включая анимации, keyframes, позиционирование и адаптивное поведение.
Это делает экран загрузки фактически настраиваемым без необходимости каждый раз модифицировать исходный код плагина при изменении анимации.
Встроенный редактор администратора
Плагин также предоставляет небольшой встроенный редактор администратора для управления пользовательским экраном загрузки.
Он добавляет отдельный раздел Splash HTML Builder в административный интерфейс Discourse, с отдельными редакторами для:
- Пользовательского HTML
- Пользовательского CSS
Изменения можно сохранять непосредственно из административного интерфейса без ручного редактирования соответствующих параметров сайта.
Базовые параметры по-прежнему остаются:
splash_custom_htmlsplash_custom_css
Редактор — это просто более удобный интерфейс для их управления.
Это также означает, что плагину не требуется модифицировать файлы исходного кода плагина каждый раз, когда нужно изменить анимацию экрана загрузки.
Пример
Пользовательский экран загрузки может содержать несколько независимых слоев:
<div class="ring-layer">
<svg viewBox="0 0 500 500">
...
</svg>
</div>
<div class="logo-layer">
<svg viewBox="0 0 500 500">
...
</svg>
</div>
И каждый слой может иметь свою собственную анимацию:
#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);
}
}
SVG остаются статичными, в то время как окружающие HTML-слои анимируются.
Это позволяет создавать значительно более сложные анимации экрана загрузки, сохраняя при этом дорогостоящие операции анимации вне самого SVG.
Почему бы просто не переопределить основной шаблон экрана загрузки?
Еще одной важной целью было избежать поддержки копии основного шаблона экрана загрузки Discourse.
Прямой подход состоял бы в том, чтобы переопределить:
app/views/common/_discourse_splash.html.erb
и скопировать текущую реализацию Discourse в плагин.
Проблема в том, что это создает нагрузку на поддержку.
Если Discourse изменит свою реализацию экрана загрузки в будущей версии, плагин по-прежнему будет содержать старую версию.
Это потенциально может привести к:
- потере новых изменений в ядре
- потере улучшений производительности
- нарушению работы после обновления Discourse
- необходимости вручную сравнивать шаблон плагина с основным после каждого обновления
Я хотел полностью избежать этого.
Основной fallback (запасной вариант)
Поэтому плагин поддерживает пользовательский экран загрузки с основным fallback.
Настроен пользовательский HTML
Если:
SiteSetting.splash_custom_html.present?
то плагин отображает пользовательский экран загрузки.
Пользовательский HTML пуст
Если пользовательский экран загрузки не настроен, плагин использует текущий основной шаблон экрана загрузки Discourse.
Плагин находит фактический основной файл из работающей установки Discourse:
Rails.root/app/views/common/_discourse_splash.html.erb
и отображает эту реализацию.
Концептуально:
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
Это означает, что плагин не содержит вторую копию основного шаблона экрана загрузки.
Соображения производительности
Плагин не пытается утверждать, что каждая CSS-анимация волшебным образом станет ускоренной GPU.
Браузер по-прежнему решает, как отдельные анимации рендерятся и композитируются.
Цель состоит в том, чтобы дать браузеру гораздо более благоприятную структуру для аппаратно-ускоренного композитинга:
- держать содержимое SVG статичным
- изолировать независимо анимируемые элементы
- анимировать HTML-слои
- предпочитать
transformдля перемещения/масштабирования/вращения - избегать ненужно затратных операций перерисовки
- использовать
will-changeтам, где это уместно
Например:
#d-splash .ring-layer {
will-change: transform;
animation: rotate 2.2s linear infinite;
}
Этот подход особенно хорошо сработал для моего случая использования и устранил заикания на мобильных устройствах, которые я наблюдал с оригинальной SVG-анимацией.
Включение или отключение пользовательского экрана загрузки
Плагин также предоставляет параметр сайта custom_splash_html_builder_enabled.
Когда он отключен, используется стандартный экран загрузки Discourse, независимо от того, настроены ли пользовательский HTML или CSS.
Это обеспечивает дополнительный предохранительный выключатель для временного отключения пользовательского экрана загрузки без удаления сохраненного HTML/CSS.
Пользовательский экран загрузки отображается только тогда, когда оба условия выполняются:
custom_splash_html_builder_enabled = true
splash_custom_html не пуст
В противном случае используется текущий основной экран загрузки Discourse.
Что наиболее важно, он предоставляет способ создать пользовательскую анимированную заставку, которая работает гораздо лучше на мобильных устройствах, за счет анимации HTML-слоев вокруг статичного содержимого SVG, а не прямой анимации самого SVG.