Задержка между загрузкой страницы и её отображением – частая проблема даже у оптимизированных веб-проектов. Прелоадер решает эту задачу, позволяя пользователю увидеть индикатор загрузки до появления основного контента. Это особенно актуально при работе с тяжёлыми изображениями, асинхронными скриптами или API-запросами.
Прелоадер на чистом JavaScript не требует подключения сторонних библиотек. Он может отслеживать события загрузки DOMContentLoaded и window.onload, реагируя на завершение инициализации DOM или полной загрузки всех ресурсов. Это даёт контроль над точкой, в которой можно безопасно скрыть прелоадер и отобразить интерфейс.
Важно учитывать поведение анимации и доступность. Простая CSS-анимация, управляемая через JavaScript, работает без потерь производительности. Необходимо обеспечить отключение прелоадера по таймауту в случае сетевых задержек, чтобы избежать зависания интерфейса. Оптимальная длительность ожидания – не более 10 секунд.
Поддержка адаптивности и плавного перехода между прелоадером и основным контентом критична для мобильных устройств. Использование requestAnimationFrame вместо setTimeout для плавного скрытия может снизить нагрузку на процессор и повысить отзывчивость UI.
Выбор типа прелоадера: анимация, индикатор загрузки или изображение
Анимация подходит для проектов с акцентом на визуальное восприятие. CSS-анимации не требуют JavaScript и минимально нагружают браузер. SVG-анимации дают гибкость и масштабируемость, особенно в связке с SMIL или CSS keyframes. Для сложных эффектов стоит использовать requestAnimationFrame, избегая setInterval во избежание разрыва кадров при слабом соединении.
Индикатор загрузки (progress bar или числовой процент) уместен, если известен точный объём данных. В связке с XMLHttpRequest или Fetch API можно отслеживать событие progress и обновлять элемент DOM. Пример: индикатор загрузки больших изображений, PDF или AJAX-запросов. Такой тип повышает прозрачность загрузки, снижая вероятность ухода пользователя.
Изображение используется, если необходим брендинг в ожидании загрузки. Например, логотип компании или тематическая иллюстрация. Изображение должно быть векторным (SVG) или в формате WebP для минимизации веса. Ключевой риск – само изображение может грузиться дольше основного контента. Чтобы избежать этого, используйте preload или встроите SVG прямо в HTML.
Выбор зависит от технических условий проекта. Если нет возможности отслеживать прогресс – анимация предпочтительнее. Если важна информативность – индикатор. Если приоритет – фирменный стиль – изображение.
Создание HTML-разметки и стилей для прелоадера
В основе прелоадера находится контейнер с фиксированным позиционированием, перекрывающий весь вьюпорт. Для разметки достаточно одного элемента-обёртки и вложенного в него анимированного блока:
<div id="preloader">
<div class="loader"></div>
</div>
Контейнер #preloader должен иметь position: fixed, ширину и высоту 100%, фон, соответствующий стилю сайта, и высокий z-index:
#preloader {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #ffffff;
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
Внутри .loader реализуется анимация. Простейший вариант – круговой спиннер с border-анимацией:
.loader {
width: 60px;
height: 60px;
border: 6px solid #e0e0e0;
border-top-color: #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
Ключевая анимация задаёт вращение:
@keyframes spin {
to {
transform: rotate(360deg);
}
}
Такой подход обеспечивает максимальную совместимость, не требует сторонних библиотек и легко масштабируется под любые визуальные задачи.
Управление отображением прелоадера с помощью JavaScript
Для управления прелоадером следует использовать события загрузки и состояния DOM. Прелоадер должен отображаться сразу после начала загрузки страницы и скрываться только после полной инициализации контента. Это минимизирует вероятность показа неполного интерфейса.
Создайте элемент прелоадера в HTML с уникальным идентификатором, например id="preloader"
. Пример JavaScript-кода для его скрытия:
window.addEventListener('load', function() {
const preloader = document.getElementById('preloader');
if (preloader) {
preloader.style.opacity = '0';
preloader.style.pointerEvents = 'none';
setTimeout(() => {
preloader.remove();
}, 500); // время на плавное исчезновение
}
});
Использование события DOMContentLoaded
недостаточно, так как оно срабатывает до загрузки изображений и других ресурсов. Следует использовать window.load
для полной гарантии готовности страницы.
Если используется асинхронная загрузка данных или динамическая инициализация, необходимо вручную управлять состоянием прелоадера. Пример:
async function initApp() {
const preloader = document.getElementById('preloader');
try {
const data = await fetch('/api/data');
const json = await data.json();
renderData(json);
} finally {
if (preloader) preloader.remove();
}
}
window.addEventListener('load', initApp);
При использовании SPA-фреймворков, таких как Vue или React, прелоадер можно отключать после завершения инициализации корневого компонента, используя колбэк mounted
или componentDidMount
.
Не рекомендуется скрывать прелоадер с таймером без учёта реального состояния загрузки – это приводит к визуальным сбоям и снижает воспринимаемую производительность.
Ожидание полной загрузки контента перед скрытием прелоадера
Прелоадер должен оставаться видимым до полной загрузки всех критичных ресурсов: изображений, скриптов и стилей. Использование события window.onload обеспечивает запуск функции только после завершения загрузки всего содержимого, включая медиафайлы:
window.addEventListener(‘load’, () => {
document.getElementById(‘preloader’).style.display = ‘none’;
});
Если используются асинхронные модули, динамическая подгрузка контента или внешние API, необходимо дополнительно отслеживать их завершение. Это достигается через промисы, которые объединяются с помощью Promise.all:
Promise.all([imageLoaded(), fetchData(), loadFonts()]).then(() => {
document.getElementById(‘preloader’).classList.add(‘hidden’);
});
Не полагайтесь на фиксированные таймеры (setTimeout) – они не учитывают реальные задержки загрузки и могут привести к показу незагруженного интерфейса.
Для изображений, добавляемых динамически, проверяйте свойство complete и подписывайтесь на событие load:
const img = new Image();
img.src = ‘example.jpg’;
if (img.complete) {
resolve();
} else {
img.onload = () => resolve();
}
Не забывайте удалять прелоадер из DOM после его скрытия, чтобы исключить влияние на производительность:
const preloader = document.getElementById(‘preloader’);
preloader.addEventListener(‘transitionend’, () => preloader.remove());
Точное управление моментом скрытия прелоадера обеспечивает стабильный пользовательский опыт и предотвращает отображение недозагруженного интерфейса.
Удаление прелоадера из DOM после завершения загрузки
Прелоадер необходимо удалить из DOM сразу после полной загрузки всех ресурсов страницы, чтобы избежать лишней нагрузки и конфликтов в интерфейсе. Для этого используется событие window.onload, которое гарантирует, что не только HTML-документ, но и все изображения, стили и скрипты уже загружены.
Пример кода:
window.onload = function () {
const preloader = document.getElementById('preloader');
if (preloader) {
preloader.remove();
}
};
Важно: не используйте display: none для скрытия прелоадера после загрузки – это оставляет элемент в DOM и может повлиять на производительность. Метод remove() полностью исключает узел из дерева документа.
Если требуется поддержка старых браузеров, где remove() недоступен, используйте:
preloader.parentNode.removeChild(preloader);
Для повышения отзывчивости интерфейса, оберните удаление в setTimeout с короткой задержкой (например, 100–200 мс), если вы используете анимации исчезновения. Это позволяет завершить CSS-анимацию до удаления элемента.
Рекомендуется также очистить все связанные с прелоадером таймеры или обработчики событий, чтобы избежать утечек памяти при длительной работе страницы.
Добавление прелоадера при переходах между страницами SPA
В одностраничных приложениях (SPA) навигация осуществляется без полной перезагрузки страницы, поэтому важно вручную управлять отображением прелоадера при смене маршрута. Ниже – конкретный подход для реализации на основе событий маршрутизации.
- Если используется библиотека маршрутизации (например, React Router, Vue Router или аналог), используйте хуки жизненного цикла маршрутов для отслеживания начала и окончания перехода.
- Создайте глобальный компонент прелоадера, который будет отображаться поверх контента и скрываться по завершении загрузки новой страницы или данных.
Пример на React с использованием React Router v6:
import { useLocation } from 'react-router-dom';
import { useEffect, useState } from 'react';
function Preloader() {
const [loading, setLoading] = useState(false);
const location = useLocation();
useEffect(() => {
setLoading(true);
const timer = setTimeout(() => setLoading(false), 500); // Заменить на реальные данные загрузки
return () => clearTimeout(timer);
}, [location]);
return loading ? <div className="preloader">Загрузка...</div> : null;
}
- Не используйте фиксированные таймеры в продакшене. Вместо этого привяжите отображение прелоадера к фактическим событиям загрузки данных (например, fetch-запросы, lazy-загрузка компонентов).
- В библиотеках с асинхронной подгрузкой компонентов (React.lazy, Vue async components) оборачивайте контент в Suspense с fallback – это даст нативную точку для отображения прелоадера.
Также важно:
- Обязательно предотвращайте «мерцание» – не скрывайте прелоадер, пока новая страница полностью не готова.
- Не блокируйте пользовательский ввод, если прелоадер не критичен для UX – используйте полупрозрачные оверлеи или индикаторы на уровне конкретных блоков.
- Подключайте прелоадер как часть layout-компонента, чтобы он автоматически реагировал на смену маршрута без необходимости дублировать код.