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-анимаций или использовать готовые библиотеки, если нужна гибкость и расширенные возможности.

Опубликовано 18 мая 20258 минут чтенияМария Исаева
Средний рейтинг статьи — 4.8

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

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