Skeleton Loading в React без Tailwind: как сделать скелетон

8 минут чтения
Средний рейтинг статьи — 4.8

Skeleton Loading — это техника отображения заглушек ("скелетов") вместо контента, который ещё загружается. Такая визуализация делает интерфейс более отзывчивым и предсказуемым, снижает восприятие задержки и улучшает пользовательский опыт. В этой статье мы разберём, как реализовать Skeleton UI в React без использования CSS-фреймворков вроде Tailwind.

Почему Skeleton лучше обычного спиннера

Когда пользователь видит крутящийся индикатор загрузки, он не понимает, что конкретно загружается. Skeleton показывает будущую структуру интерфейса — прямоугольники, кружки, полосы, имитирующие текст или аватары. Это даёт понимание, что появится, и визуально ускоряет процесс ожидания.

Создание базового Skeleton-компонента

Создадим простой переиспользуемый компонент, который будет отображать "пульсирующий" блок-заглушку с заданными размерами.

// components/Skeleton.js
import React from 'react';
import './Skeleton.css';
 
export function Skeleton({ width = '100%', height = '16px', borderRadius = '4px', style = {} }) {
  return (
    <div
      className="skeleton"
      style={{
        width,
        height,
        borderRadius,
        ...style,
      }}
    ></div>
  );
}

Создадим CSS-анимацию для эффекта пульсации:

/* Skeleton.css */
.skeleton {
  background-color: #e0e0e0;
  position: relative;
  overflow: hidden;
}
 
.skeleton::after {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  height: 100%;
  width: 100%;
  background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.4), transparent);
  animation: shimmer 1.2s infinite;
}
 
@keyframes shimmer {
  100% {
    left: 100%;
  }
}

Такой компонент можно использовать в любых местах интерфейса. Он не зависит от сторонних библиотек и легко настраивается через props.

Пример использования в карточке пользователя

Теперь создадим компонент, который имитирует карточку пользователя в состоянии загрузки. Здесь мы используем скелетоны для аватара и текстовых блоков:

// components/UserCardSkeleton.js
import React from 'react';
import { Skeleton } from './Skeleton';
 
export function UserCardSkeleton() {
  return (
    <div style={{ display: 'flex', alignItems: 'center', padding: '12px', border: '1px solid #ccc', borderRadius: '8px', marginBottom: '8px' }}>
      <Skeleton width="48px" height="48px" borderRadius="50%" style={{ marginRight: '16px' }} />
      <div style={{ flex: 1 }}>
        <Skeleton width="60%" height="16px" style={{ marginBottom: '8px' }} />
        <Skeleton width="40%" height="14px" />
      </div>
    </div>
  );
}

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

Подключение в компонент с состоянием загрузки

Теперь подключим скелетон в основной компонент, который получает данные пользователя. Пока данные загружаются — показываем UserCardSkeleton, после — полноценную карточку:

import React, { useEffect, useState } from 'react';
import { UserCardSkeleton } from './UserCardSkeleton';
 
export function UserCard() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
 
  useEffect(() => {
    fetch('/api/user')
      .then(res => res.json())
      .then(data => {
        setUser(data);
        setLoading(false);
      });
  }, []);
 
  if (loading) return <UserCardSkeleton />;
 
  return (
    <div style={{ display: 'flex', alignItems: 'center', padding: '12px', border: '1px solid #ccc', borderRadius: '8px' }}>
      <img
        src={user.avatar}
        alt={user.name}
        style={{ width: '48px', height: '48px', borderRadius: '50%', marginRight: '16px' }}
      />
      <div>
        <p style={{ fontWeight: 'bold', margin: 0 }}>{user.name}</p>
        <p style={{ color: '#666', margin: 0 }}>{user.email}</p>
      </div>
    </div>
  );
}

Здесь мы эмулируем API-запрос с задержкой. Пока данные не пришли, отображается компонент UserCardSkeleton, который занимает нужное место и помогает избежать "прыжков" интерфейса при появлении настоящих данных.

Заключение

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

8 минут чтения
Средний рейтинг статьи — 4.8

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний