Loaders✨ Premium

List Skeleton

Four list rows [40 px avatar + 2 lines] in pure CSS: synchronized 1.8 s shimmer across 12 bones, line widths varying from row to row.

CSSShimmerListe

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Loaders has 29 effects, including 4 free. Explore the category →

3 usage examples

Conversations loading — mobile messaging app — List Skeleton example 1

① Conversations loading — mobile messaging app

WhenOpening a messaging application: the conversation list fills in during the initial fetch. The skeleton immediately occupies the area and stabilizes the page height.
WhyEach skeleton row (circle + 2 lines) mirrors the exact structure of a conversation (profile photo + name + last message preview) — no layout shift when the real content arrives.
Settings6 items instead of 4 to fill a 667 px screen; avatar at 48 px; list-skel-line1 at 14 px (name); list-skel-line2 at 10 px (preview); .list-skel { width: 100% }.
Recipient picker — autocomplete results panel — List Skeleton example 2

② Recipient picker — autocomplete results panel

WhenInput field with a suggestion panel: the user types a name, the panel opens with the skeleton while the API responds (typically 150–400 ms).
WhyA 3-item skeleton takes up exactly the height of a standard result list, preventing a visual jump. The varying line widths (70/60/80%) simulate names of different lengths.
Settings3 items; avatar at 36 px; gap raised to 6 px; .list-skel { width: 100%; border-radius: 8px; overflow: hidden }; shimmer slightly faster at 1.4s to signal a short wait.
Activity feed — dashboard sidebar — List Skeleton example 3

③ Activity feed — dashboard sidebar

WhenSide panel listing recent events (commit, payment, comment): it renders at page load while the main header and KPIs are already visible.
WhyThe avatar represents the action's author, the top line the event title (12 px) and the bottom line the timestamp or context (9 px) — the size hierarchy in the code matches the real typographic hierarchy without modification.
Settings5 items; padding: 8px 12px for compact rows; gap: 6px; .list-skel { width: 100% }; avatar at 32 px.

How it works

The code creates four .list-skel-item blocks inside a .list-skel container 280 px wide, arranged in a column (flex-direction: column, gap: 4px). Each item is a horizontal flex row with padding: 12px 16px, a rgba(255,255,255,.02) background and 12 px rounded corners. It holds a .skel-bone-circle .list-skel-avatar circle (40×40 px, flex-shrink: 0) and a text block .list-skel-text (flex: 1) with two bones: .list-skel-line1 (height 12 px, bottom margin 8 px) and .list-skel-line2 (height 9 px). The classes .skel-bone and .skel-bone-circle give each bone the rgba(255,255,255,.08) background and relative positioning needed by the shimmer pseudo-element. The HTML holds 12 animated bones in total (4 circles + 4 primary lines + 4 secondary lines).

Line widths vary from item to item via inline style attributes on the relevant bones: list-skel-line1 at 70% (CSS default), 60%, 80%, 50%; list-skel-line2 at 50% (CSS default), 40%, 55%, 35%. These variations are static and hard-coded in the HTML — no JavaScript generates them. The first item has no style attribute: its widths come from the CSS rules (.list-skel-line1 at 70%, .list-skel-line2 at 50%).

The shimmer is produced by each bone's ::after pseudo-element, at position: absolute; inset: 0, with background linear-gradient(90deg, transparent 0, rgba(255,255,255,.1) 50%, transparent 100%) on a background-size: 200% 100%. The shimmerSlide animation moves this background from background-position: -200% to 200% in 1.8 s ease-in-out, delay 0 s, infinite. All 12 bones share the same delay: the shimmer is synchronized, not staggered. Zero JavaScript — the entire effect is pure CSS.

Accessibility

  • prefers-reduced-motion not handled: measured under reducedMotion: 'reduce' (Playwright/Chromium), all 12 animations keep running (animationPlayState: running, animationDuration: 1.8s). Add @media (prefers-reduced-motion: reduce) { .skel-bone::after, .skel-bone-circle::after { animation: none } }.
  • The skeleton is a loading indicator, not content: set role="status" or aria-busy="true" on the parent container of the real list (not on .list-skel itself), and remove .list-skel from the DOM once the content has arrived. No alt text is needed on the bones.
  • Set aria-hidden="true" on .list-skel: the 12 empty bones must not be traversed by screen readers. Announce the end of loading through an existing aria-live="polite" region in your interface.
  • The bone background (rgba(255,255,255,.08)) and shimmer flash (rgba(255,255,255,.1)) only make sense on a dark background. On a light background, bones and shimmer both become invisible: replace with rgba(0,0,0,.06) and rgba(0,0,0,.08).

Browser compatibility

Pure CSS, no JavaScript. Requires @keyframes, animation, the inset shorthand (Chrome 87+, Firefox 87+, Safari 14.1+), border-radius: 50%, display: flex and overflow: hidden. No dependencies.

Chrome 87+✓ Full
Firefox 87+✓ Full
Safari 14.1+✓ Full
Edge 87+✓ Full
Mobile iOS 14.5+✓ Full
Android Chrome✓ Full

Without CSS or on a browser older than Safari 14.1 (missing inset shorthand), the ::after pseudo-elements do not position themselves and the shimmer is invisible — the bones remain plain dark rectangles and circles with no animation, which is an acceptable fallback for a loading state.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="list-skel">
  <div class="list-skel-item">
    <div class="skel-bone-circle list-skel-avatar"></div>
    <div class="list-skel-text">
      <div class="skel-bone list-skel-line1"></div>
      <div class="skel-bone list-skel-line2"></div>
    </div>
  </div>
  <!-- … 3 more items, e.g. list-skel-line1 style="width:60%" and list-skel-line2 style="width:40%" -->
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Number of items (HTML — .list-skel-item blocks) 4 Duplicate or remove blocks. Each item adds ~65 px of height (40 px avatar + paddings + gap). For realistic line widths, vary the style="width:…" attributes from item to item.
Avatar size (CSS — .list-skel-avatar { width; height }) 40×40 px The avatar is vertically centered in the item by align-items: center. At 48 px it represents a profile photo; at 32 px a compact icon. Change both properties together.
Primary line height (CSS — .list-skel-line1 { height }) 12 px Targets the title or name in the row. 14px to align with body text at font-size: 14px; 10px for a denser list.
Secondary line height (CSS — .list-skel-line2 { height }) 9 px Targets the subtitle, timestamp or summary. Keeping a ratio ≥ 0.7 relative to the primary line preserves the hierarchy when real content arrives.
Line widths (HTML — style="width:…" on each bone) Line1: 70 / 60 / 80 / 50% — Line2: 50 / 40 / 55 / 35% CSS default widths (70% / 50%) apply when the attribute is absent. Vary the values to simulate content of different lengths; values that are too similar make the list look uniform and less convincing.
Gap between items (CSS — .list-skel { gap }) 4 px 0 = seamless list without visible separation (feed style); 8px = distinct entries, similar to an 8 px spacer between cards. Beyond 12 px, the list feel is lost.
Shimmer duration (CSS — animation: 1.8s ease-in-out 0s infinite) 1.8 s Edit the duration in the animation declaration on the .skel-bone-circle::after, .skel-bone::after selector. 1.2s conveys urgency; 2.5s suggests a slow or lazy load.

FAQ

Because all bones share the same animation delay: animation: 1.8s ease-in-out 0s infinite, delay 0 s. For a cascading wave effect, add an increasing delay to each item: .list-skel-item:nth-child(2) .skel-bone::after, .list-skel-item:nth-child(2) .skel-bone-circle::after { animation-delay: .15s }, and so on with a 0.15 s increment per rank.
Card Skeleton represents a single card block (header, 120 px image, three text lines) — a single object. List Skeleton repeats the same compact row (40 px circle + 2 lines) four times across 268 px of height, with no image and no outer border — it is a list. Choose Card Skeleton when the final content is a detail card; choose List Skeleton when it is a list of results, conversations or events.
No. The bone background is rgba(255,255,255,.08) and the shimmer flash is rgba(255,255,255,.1) — two translucent whites, invisible on a white or light-grey surface. On a light background, replace these values with rgba(0,0,0,.06) and rgba(0,0,0,.08) in the .skel-bone, .skel-bone-circle and .skel-bone-circle::after, .skel-bone::after selectors.