Гид по технологиям

Эффект «скелетного» экрана: как сделать плавную загрузку профиля (HTML/CSS/JS)

• 4 min read • Frontend • Обновлено 19 Nov 2025
Скелетный экран: плавная загрузка профиля
Скелетный экран: плавная загрузка профиля

Визуальная иллюстрация окна на Mac

Зачем нужны скелетные экраны

Скелетные экраны показывают упрощённую версию интерфейса вместо пустой страницы. Они:

  • уменьшают субъективное время загрузки;
  • задают ожидание пользователя о том, где появится контент;
  • помогают избежать Cumulative Layout Shift (CLS), потому что область контента зарезервирована заранее.

Важно: скелет не ускоряет загрузку данных, он улучшает восприятие скорости. CLS — это изменение расположения элементов после рендера; фиксированные блоки и предустановленные размеры уменьшают CLS.

Дизайн структуры страницы

Дизайн макета веб-страницы

Проектирование макета помогает зафиксировать ожидания. Определите цель страницы, основную структуру и набор компонентов. Для примера используем простую карточку профиля с обложкой, аватаром, текстом и CTA-кнопками.

Шаги:

  1. Нарисуйте макет на бумаге или в Figma/Adobe XD.
  2. Определите адаптивные точки (например, 560px для мобайла).
  3. Проставьте размеры для ключевых областей: обложка, аватар, блоки текста.

После этого переходите к HTML-структуре.

Базовая HTML-структура

Создайте файл index.html и поместите разметку внутри контейнера с классом profile-container. Добавляйте класс skeleton к тем элементам, где хотите видеть эффект загрузки. Этот класс будет удалён через JavaScript, когда данные загрузятся.

Пример HTML:




  
  
  
  
  Skeleton Screen Loading Effect


  
Обложка профиля
Аватар пользователя

John Doe

Software Engineer @ Google || Full Stack Developer || Self Taught

Bengaluru, Karnataka, India • Contact info

534 connections

Примечание: не забудьте подключить style.css и script.js в head/ниже по телу документа соответственно.

Базовые стили

Добавьте базовые правила для body: отступы, шрифт и цвет.

body {
  margin: 0;
  font-family: Arial, sans-serif;
  color: rgba(255, 255, 255, 0.9);
  background-color: #0f1112;
}

Добавление эффекта загрузки (шиммер)

Скелет реализуется через класс .skeleton, невидимый контент и псевдоэлемент ::after с градиентом, который сдвигается слева направо.

.skeleton {
  position: relative;
  width: max-content;
  overflow: hidden;
  border-radius: 4px;
  background-color: #1e2226 !important;
  color: transparent !important;
  border-color: #1e2226 !important;
  user-select: none;
  cursor: default;
}

.skeleton img {
  opacity: 0;
}

.skeleton::after {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  transform: translateX(-100%);
  background-image: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0) 0,
    rgba(255, 255, 255, 0.12) 20%,
    rgba(255, 255, 255, 0.26) 60%,
    rgba(255, 255, 255, 0)
  );
  animation: shimmer 2s infinite;
  content: '';
}

@keyframes shimmer {
  100% {
    transform: translateX(100%);
  }
}

Совет: уменьшите прозрачность и длительность у тёмных тем, чтобы эффект выглядел аккуратно.

Добавление эффекта загрузки

Стили для изображений и контейнера

img {
  width: 100%;
  vertical-align: middle;
}

.profile-container {
  width: 95%;
  max-width: 780px;
  margin: 32px auto 0;
  border-radius: 8px;
  background-color: #1e2226;
  overflow: hidden;
  position: relative;
}

.cover-img {
  width: 100%;
  overflow: hidden;
  background-color: #1e2226;
  aspect-ratio: 4 / 1;
}

.profile-img {
  border-radius: 50%;
  width: 160px;
  height: 160px;
  border: 4px solid #000;
  background-color: #1e2226;
  margin: 0 auto;
  position: relative;
  overflow: hidden;
  bottom: 100px;
}

Адаптивность

Добавьте медиазапросы для мобильных экранов:

@media (max-width: 560px) {
  .profile-img {
    width: 100px;
    height: 100px;
    bottom: 60px;
  }
}

Стили текста и CTA

.profile-text {
  margin-top: -80px;
  padding: 0 16px;
}

.profile-text h1 {
  margin-bottom: 0;
  font-size: 24px;
  overflow: hidden;
}

.profile-text p { margin: 4px 0; overflow: hidden; }

.profile-text h5 {
  margin-top: 4px;
  font-size: 14px;
  margin-bottom: 8px;
  font-weight: 400;
  color: #ffffff99;
  overflow: hidden;
}

.profile-text a {
  color: #70b5f9;
  font-size: 14px;
  text-decoration: none;
  font-weight: 600;
}

.profile-text a:hover { text-decoration: underline; }

.profile-cta { padding: 16px 16px 32px; display: flex; }

.profile-cta a { padding: 6px 16px; border-radius: 24px; text-decoration: none; display: block; }

.message-btn { background-color: #70b5f9; color: #000; }

.more-btn { color: inherit; border: 1px solid rgba(255,255,255,0.9); margin-left: 8px; }

Стилизация компонентов

Отключение скелета через JavaScript

Когда данные готовы, удалите класс .skeleton. Ниже простой пример: спустя 4000 мс класс удалится у всех элементов.

// script.js
const skeletons = document.querySelectorAll('.skeleton');

skeletons.forEach((skeleton) => {
  setTimeout(() => {
    skeleton.classList.remove('skeleton');
    // при необходимости убрать inline-стили или показать img
    const img = skeleton.querySelector('img');
    if (img) img.style.opacity = '1';
  }, 4000);
});

Примечание: вместо фиктивного setTimeout используйте событие загрузки данных (fetch/axios или callback), чтобы убрать скелет сразу после получения контента.

Эффект скелета при помощи JavaScript

Когда скелетные экраны лучше, а когда — нет

Важно понимать слабые стороны метода:

  • Неэффективно при очень медленном соединении, когда данные загружаются десятки секунд — пользователь может устать от бесконечного шиммера.
  • Если структура контента сильно варьируется, заранее зарезервировать место сложно — возможны погрешности в макете.
  • Для очень простых страниц спиннер может быть легче в реализации.

Альтернативы и дополнения:

  • Прогрессивные плейсхолдеры (placeholder text) для текстового контента;
  • Ленивая загрузка изображений (lazy-loading) вместе со скелетом;
  • Skeleton + частичная гидратация: показывать реальные данные по мере готовности блоков.

Методология внедрения (мини-план)

  1. Проанализировать критичные страницы и определить элементы, которые чаще всего меняют размер.
  2. Нарисовать скелеты для каждого ключевого блока.
  3. Добавить CSS-классы и шиммер.
  4. Подключить удаление .skeleton при успешной загрузке данных.
  5. Протестировать на мобильных и слабых соединениях.
  6. Измерить CLS и поведение с пользователями (если есть аналитика).

Критерии приёмки

  • Все ключевые блоки показывают плейсхолдеры до получения данных.
  • CLS измеренно не увеличивается после загрузки (визуально макет не «прыгает»).
  • Изображения становятся видимыми без резких сдвигов.
  • Эффект отключается сразу после получения данных (нет статического шиммера).

Чек-листы по ролям

Дизайнер:

  • Определил размеры блоков для всех состояний.
  • Подготовил макеты для мобильных и десктопа.

Frontend-разработчик:

  • Реализовал классы .skeleton и шиммер.
  • Убрал класс при получении данных, показал контент без мерцания.

QA-инженер:

  • Проверил отображение при разных скоростях сети.
  • Проверил отсутствие CLS при загрузке.

Тест-кейсы (ключевые)

  1. Проверка на 3G: страница показывает скелеты, затем данные появляются без смещения.
  2. Проверка с отключённым JavaScript: контент либо рендерится сервером, либо показывается запасной контент.
  3. Эмуляция частичной загрузки: сначала появляется текст, потом изображение — оба перехода плавные.

Ментальные модели и эвристики

  • Перцепция скорости важнее реальной скорости: пользователи оценивают сайт по тому, что он показывает, а не по тому, сколько байт скачано.
  • Reserve-first: резервируйте место для контента заранее, чтобы избежать CLS.
  • Graceful-fallback: если скрипт не сработал, страница всё равно должна быть читаемой.

Простая схема принятия решения (Mermaid)

flowchart TD
  A[Нужно ли скелетный экран?] -->|Контент динамический| B[Да]
  A -->|Статическая страница| C[Нет]
  B --> D{Размеры блоков предсказуемы?}
  D -->|Да| E[Реализовать скелет]
  D -->|Нет| F[Использовать спиннер/плейсхолдеры]

Советы по оптимизации и безопасность

  • Загружайте минимально необходимые данные первыми (critical path).
  • Для изображений используйте размеры width/height или CSS aspect-ratio, чтобы не допустить прыжков макета.
  • Не храните в скелетах чувствительную информацию.

Краткий глоссарий

  • CLS: Cumulative Layout Shift, метрика непреднамеренных сдвигов макета.
  • Шиммер: движущийся градиент, создающий эффект «сверкающего» плейсхолдера.
  • Skeleton screen: визуальный плейсхолдер структуры контента.

Резюме

Скелетные экраны — простой и эффективный способ улучшить восприятие скорости и снизить CLS. Реализация сводится к трём шагам: проектирование макета, CSS-шиммер и отключение плейсхолдеров после загрузки данных. Протестируйте поведение на разных скоростях и устройцах и настройте время/стили для вашей аудитории.

Важно: выбирайте подходящий инструмент для вашей ситуации — иногда проще и эффективнее использовать ленивую загрузку или спиннеры для узких случаев.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро