Advertisement

Staggered Gradient Skeleton Loader

| by Vladimir | 2 min read | code by Rob Stinson
Beginner

Tech & Dependencies

HTML CSS JavaScript
Tailwind CSS Vue.js

Features

  • Staggered Animation
  • Computed Delays
  • Responsive Grid
  • Dark Mode

Browser Support

Chrome 100+ Edge 100+ Safari 14+ Firefox 90+

Core

This Staggered Gradient Skeleton Loader improves perceived performance by providing a visual structure while content fetches in the background. Unlike static placeholders, this Vue.js component utilizes a calculated delay system to create a “wave” animation across the grid, guiding the user’s eye naturally from top-left to bottom-right without using complex JavaScript animation libraries.

Core Technique (The “How”)

The effect is achieved by combining standard CSS background animation with Vue’s dynamic style binding capabilities.

1. The Shimmer Effect

The visual “loading” pulse is a standard CSS trick. We create a gradient that is double the size of the container (200%) and animate its background position. This creates a smooth highlight moving across the dark slate element.

.bg-animate {
  /* Dark slate to lighter slate gradient */
  background: linear-gradient(-45deg, #334155, #1e293b);
  background-size: 200% 200%;
  animation: gradient 1s ease infinite;
}

@keyframes gradient {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

2. Calculated Staggering (Vue Logic)

The defining feature of this snippet is the sequential delay. Instead of all cards pulsing simultaneously (which can look robotic), each card’s animation starts slightly later than the previous one.

Defining specific classes for every delay would be tedious. Instead, we use Vue’s :style binding to calculate the animation-delay inline based on the item’s index or ID.

<!-- Iterate through cards -->
<div v-for="card in cards" :key="card.id">
  
  <!-- 
    Dynamic Delay Calculation:
    ID 1 = 0.25s delay
    ID 2 = 0.50s delay
    etc.
  -->
  <div
     class="bg-animate rounded-lg aspect-video"
     :style="{ animationDelay: card.id * 0.25 + 's' }">
  </div>

  <!-- Detailed elements inherit the same calculation logic -->
  <span 
      class="w-5/6 h-4 bg-animate"
      :style="{ animationDelay: card.id * 0.25 + 's' }">
  </span>
</div>

Accessibility (A11y)

While visually effective, this snippet requires a few additions to be fully accessible.

  • ARIA Attributes: The skeleton elements are purely decorative. You should add aria-hidden="true" to the container so screen readers do not try to announce empty or meaningless elements.
  • Loading State: Ensure the parent container has aria-busy="true" or a visually hidden text stating “Loading content…” is present.
  • Reduced Motion: The pulsing animation can trigger vestibular disorders. Wrap the animation in a media query to disable it for users who prefer reduced motion.
@media (prefers-reduced-motion: reduce) {
  .bg-animate {
    animation: none;
    background: #334155; /* Static fallback color */
  }
}

Browser Support

This snippet relies on standard CSS animations and Vue.js. It works flawlessly across all modern browsers.

Advertisement