Skeleton

Loading content…
@use 'sprucecss/scss/spruce' as *;

.skeleton-card {
  display: flex;
  gap: spacer('m');

  &__lines {
    flex-grow: 1;
    @include layout-stack('xs');
  }
}

.skeleton {
  --skeleton-base: #{color-alpha('heading', 0.08)};
  --skeleton-shine: #{color-alpha('heading', 0.16)};
  background-color: var(--skeleton-base);
  border-radius: radius('sm');

  @include motion-safe {
    animation: skeleton-shine 1.4s ease-in-out infinite;
    background-image: linear-gradient(90deg, transparent, var(--skeleton-shine), transparent);
    background-repeat: no-repeat;
    background-size: 50% 100%;
  }

  &--avatar {
    block-size: 3.5rem;
    border-radius: 50%;
    flex-shrink: 0;
    inline-size: 3.5rem;
  }

  &--title {
    block-size: 1.5rem;
    inline-size: 60%;
  }

  &--text {
    block-size: 0.875rem;
  }

  &--short {
    inline-size: 40%;
  }

  &--media {
    aspect-ratio: 16 / 9;
    border-radius: radius('lg');
  }
}

@keyframes skeleton-shine {
  from {
    background-position: -100% 0;
  }

  to {
    background-position: 200% 0;
  }
}
<div class="skeleton-card" aria-busy="true" aria-live="polite">
    <span class="sr-only">Loading content…</span>
    <div class="skeleton skeleton--avatar" aria-hidden="true"></div>
    <div class="skeleton-card__lines" aria-hidden="true">
        <div class="skeleton skeleton--title"></div>
        <div class="skeleton skeleton--text"></div>
        <div class="skeleton skeleton--text"></div>
        <div class="skeleton skeleton--text skeleton--short"></div>
    </div>
</div>
<div class="skeleton skeleton--media" aria-hidden="true"></div>

Skeleton

On this page

Placeholder shapes that show the layout of the content while it loads.

Technical Details

  • The container has aria-busy="true" and a visually hidden "Loading content…" text; the shapes are aria-hidden. Remove aria-busy when the content arrives.
  • The base and shine colors are translucent mixes of the heading color (color-alpha()), so they work on any background, in dark mode and in every style.
  • The shimmer animation runs only without the reduced motion preference; otherwise the shapes are static.
  • Shapes: --avatar, --title, --text, --short, --media; size anything else with block-size and inline-size.

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our UI library of accessible components built with Spruce CSS.

Blocks and Pages

Full-width page blocks and complete page templates, ready to copy.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.