ai-coding-demo

什么是骨架屏?

骨架屏(Skeleton Screen)是一种 加载占位符技术,在页面或数据还在加载时,先显示页面的基本结构和轮廓,用户能提前了解页面布局,给用户一种「内容正在加载」的感觉,而不是空白页面。

核心作用:减少用户等待时的焦虑感,提升感知性能,让加载过程更流畅自然。

为什么需要骨架屏?

1. 提升用户体验

2. 降低跳出率

3. 业界最佳实践

骨架屏的应用场景

场景 1:图片列表页面

电商、图片社交平台等内容密集型页面,图片加载慢时,用骨架块占位:

<!-- 骨架屏状态:显示灰色占位块 -->
<div class="skeleton-image-container">
  <div class="bg-gray-200 animate-pulse rounded-md" style="height: 200px;"></div>
</div>

<!-- 加载完成后:显示真实图片 -->
<div class="skeleton-image-container loaded">
  <img src="真实图片URL" class="rounded-md transition-opacity duration-500">
</div>

场景 2:个人信息卡片

用户资料页面,姓名、头像、简介等信息模块分别占位:

<div class="user-card">
  <!-- 头像骨架 -->
  <div class="skeleton-avatar"></div>
  <!-- 姓名骨架 -->
  <div class="skeleton-line w-3/4"></div>
  <!-- 简介骨架 -->
  <div class="skeleton-line w-1/2"></div>
</div>

场景 3:文字内容页

文章、新闻页面,标题和段落分别加载:

<article class="article">
  <!-- 标题骨架 -->
  <h1 class="skeleton-title"></h1>
  <!-- 段落骨架 -->
  <p class="skeleton-paragraph"></p>
  <p class="skeleton-paragraph"></p>
</article>

如何在网页中实现骨架屏?

方法 1:CSS + 简单动画(推荐新手)

animate-pulse 制作闪烁效果,配合灰色背景模拟加载状态:

.skeleton {
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
}

@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

方法 2:Tailwind CSS 的 animate-pulse(最简单)

Tailwind 内置了脉冲动画,直接添加类名即可:

<div class="bg-gray-200 rounded-md animate-pulse">
  <!-- 占位内容 -->
</div>

完整例子:带骨架屏的图片卡片

<div class="max-w-sm mx-auto bg-white shadow-md rounded-lg overflow-hidden">
  <!-- 加载中:骨架屏 -->
  <div class="h-48 bg-gray-200 animate-pulse"></div>

  <div class="p-4">
    <!-- 加载中:骨架文本 -->
    <div class="h-4 bg-gray-200 rounded animate-pulse mb-2"></div>
    <div class="h-4 bg-gray-200 rounded animate-pulse w-3/4"></div>
  </div>
</div>

方法 3:React/Vue 组件化(进阶)

用 JavaScript 控制显示状态,数据加载前显示骨架屏,加载完成后隐藏:

// React 示例
function UserCard({ user, loading }) {
  if (loading) {
    return (
      <div className="user-card">
        <div className="skeleton-avatar"></div>
        <div className="skeleton-text"></div>
      </div>
    );
  }

  return (
    <div className="user-card">
      <img src={user.avatar} alt={user.name} />
      <h3>{user.name}</h3>
    </div>
  );
}

骨架屏的设计原则

1. 尺寸要匹配真实内容

骨架屏的占位块大小应尽量接近真实内容(避免加载完成后跳动)

2. 颜色选择有讲究

3. 动画速度要合适

4. 形状要符合内容

骨架屏 vs 传统加载方式对比

方式 表现 用户体验
空白页面 一片空白,什么都没有 ❌ 焦虑,不知道要等多久
Spinner 转圈圈,只有进度指示 ⚠️ 知道在加载,但不知道内容结构
骨架屏 显示页面轮廓,内容占位 ✅ 知道要加载什么,心理有数

一个结合 Unsplash 图片和骨架屏的完整例子

<!DOCTYPE html>
<html>
<head>
  <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-100">
  <div class="max-w-md mx-auto bg-white shadow-md rounded-lg overflow-hidden" id="card">
    <!-- 初始状态:骨架屏 -->
    <div class="h-64 bg-gray-200 animate-pulse" id="skeleton-image"></div>

    <div class="p-4">
      <div class="h-6 bg-gray-200 rounded animate-pulse mb-2" id="skeleton-title"></div>
      <div class="h-4 bg-gray-200 rounded animate-pulse w-5/6 mb-2"></div>
      <div class="h-4 bg-gray-200 rounded animate-pulse w-4/6"></div>
    </div>
  </div>

  <script>
    // 模拟加载延迟
    setTimeout(() => {
      // 隐藏骨架屏,显示真实内容
      document.getElementById('skeleton-image').className = 'h-64 transition-all duration-500';
      document.getElementById('skeleton-image').style.background = 'none';

      // 加载图片
      const img = document.createElement('img');
      img.src = 'https://images.unsplash.com/photo-1544716278-ca5e3f4abd8c?q=80&w=2070&auto=format&fit=crop';
      img.className = 'h-64 w-full object-cover';
      img.onload = () => {
        document.getElementById('skeleton-image').innerHTML = '';
        document.getElementById('skeleton-image').appendChild(img);
      };

      // 显示文字内容
      document.getElementById('skeleton-title').className = 'h-6 text-xl font-bold text-gray-800 transition-all duration-500';
      document.getElementById('skeleton-title').innerHTML = '《代码大全》';
      document.getElementById('card').querySelectorAll('#skeleton-title + div').forEach((el, idx) => {
        el.className = idx === 0 ? 'h-4 text-gray-600 mb-2' : 'h-4 text-gray-600';
        el.innerHTML = idx === 0 ? '软件开发的实用指南' : '程序员必读经典';
      });
    }, 2000); // 2秒后加载完成
  </script>
</body>
</html>

效果:页面先显示灰色占位块(骨架屏),2秒后显示真实的 Unsplash 书籍图片和文字内容,让用户清楚知道页面在加载什么内容。