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

REST API на Node.js без Express: создаём с нуля
Узнайте, как с нуля реализовать полноценный REST API на Node.js без Express. Без фреймворков: чистый JavaScript, нативные модули, примеры и объяснения.
17 июня 20255 мин

Что такое Tailwind CSS и как с ним быстро стилизовать интерфейс
Разбираем, как Tailwind CSS помогает быстрее создавать UI без написания кастомных стилей. Почему стоит использовать утилитарный подход.
3 августа 20256 мин

Как улучшить производительность фронтенда с помощью Lazy Loading и Code Splitting
В этой статье мы рассмотрим, как ленивое (lazy) загрузка и разделение (code splitting) кода могут помочь улучшить производительность вашего фронтенда. Узнайте, как эти техники работают и как их можно внедрить в ваш проект.
6 апреля 20258 мин
Настроить мониторинг за 30 секунд
Надёжные уведомления о даунтаймах. Без ложных срабатываний