Loaders✨ Premium

Article Skeleton

Ten bones, 290 px: 130 px hero, two-line title (85/60 %), body lines tapering 100→70 %, 32 px avatar with name and date — 1.8 s CSS shimmer, no JavaScript.

CSSShimmerBlog

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

Article waiting for a fetch — reading column — Article Skeleton example 1

① Article waiting for a fetch — reading column

WhenThe page receives a slug, fires a JSON API call, and shows the skeleton during network latency (50 to 500 ms depending on cache).
WhyHero + two-line title + body + author: the structure matches a standard blog article exactly. The reader identifies the type of incoming content without any adaptation by the developer.
SettingsNo adjustment needed — the effect is delivered at the right size for a 290 px column. For a full-width layout: .article-skel { width: 100%; max-width: 680px; } and .article-skel-hero { height: 200px; }.
Technical documentation — the requested chapter loads, table of contents already in place — Article Skeleton example 2

② Technical documentation — the requested chapter loads, table of contents already in place

WhenThe reader clicks a chapter in the left-hand table of contents, already rendered with the site navigation; the page fetches the chapter content (server-compiled Markdown, 100 to 400 ms) and the skeleton fills the reading column during that delay, while the table of contents and search remain usable.
WhyA documentation chapter has exactly the anatomy of the ten bones: a header diagram (130 px hero), a two-line title (85 then 60 %), tapering paragraphs (100 → 70 %), then the author and last-updated date. The skeleton reserves the chapter's exact footprint in the column: the table of contents does not move when the content lands, and the reader knows they are waiting for illustrated prose — a spinner would reserve no height, a progress bar would not say what is coming, and Card Skeleton (avatar first) would announce a post, not a chapter.
SettingsThe sheet's setting for a reading column: .article-skel { width: 100%; max-width: 680px; } — bones expressed in % (hero, title lines, body lines) follow the width, the hero keeps its 130px for the header diagram, 1.8s duration unchanged. Set aria-busy="true" on the content column only, never on the table of contents, which must stay navigable.
Aggregator feed — multiple articles loading in parallel — Article Skeleton example 3

③ Aggregator feed — multiple articles loading in parallel

WhenA search result list or RSS feed loads several entries in parallel via Promise.all; each card shows its skeleton until its own call resolves.
WhyStacking several .article-skel cards produces a credible feed-in-progress — more informative than a global spinner for a user who knows articles are on the way. The 359 px card height lets two or three fit on screen.
SettingsReduce hero to 80px for a compact list (.article-skel-hero { height: 80px; }); remove .article-skel-title2 to simulate short titles; two body lines are enough for a list view.

How it works

The .article-skel card (290 px wide, padding: 16px, border-radius: 16px, background rgba(255,255,255,.02), border rgba(255,255,255,.05)) holds ten bones in a column. The hero image .article-skel-hero spans the full content width (256 × 130 px, border-radius: 10px, margin-bottom: 16px), followed by two title lines: .article-skel-title at 85 % (218 px, 16 px tall, margin-bottom: 8px) and .article-skel-title2 at 60 % (154 px, margin-bottom: 16px). Four .article-skel-p elements of 9 px height follow, with widths set by their position in the parent via :nth-child: child 4 at 100 % (256 px), 5 at 95 % (243 px), 6 at 88 % (225 px), 7 at 70 % (179 px) — an inverted pyramid that visually reproduces the tapering of a prose paragraph. The last gets margin-bottom: 16px; the other three get 8px. Measured total card height: 359 px.

The animation runs on the ::after pseudo-element shared by .skel-bone and .skel-bone-circle. It is positioned absolute with inset: 0 and carries a linear-gradient(90deg, transparent 0, rgba(255,255,255,.1) 50%, transparent 100%) sized at 200% 100%. The shimmerSlide animation moves background-position from −200% 0 to 200% 0, a total travel of 400 %. On a 256 px bone, the highlight sweeps through the element in roughly 25 % of the total duration — about 0.45 s of visible sweep, then 1.35 s of plain surface — over a cycle of 1.8 s (ease-in-out, 0s delay, infinite). The peak is rgba(255,255,255,.1) on a rgba(255,255,255,.08) base: an intentionally subtle highlight. All bones share the same parameters and shimmer in phase.

At the bottom of the card, .article-skel-author (flex, gap: 10px, padding-top: 14px, border-top: 1px solid rgba(255,255,255,.05)) aligns a .skel-bone-circle.article-skel-author-avatar circle of 32 × 32 px with two stacked lines on the right: name (80 × 10 px) and date (60 × 8 px, margin-top: 6px). The width hierarchy (80 then 60 px) mimics a first-name/last-name line followed by a short date. Integration note: the four body-line widths rely on :nth-child(5/6/7) of .article-skel — if any element is inserted before those lines, the positions shift and the widths no longer match the right bones. The .demo-preview wrapper present in the sold code (background #0a0a0f, centered flex, min-height: 300px) is the site's demo container; the effect starts at .article-skel.

Accessibility

  • prefers-reduced-motion not handled: no @media (prefers-reduced-motion: reduce) rule in the sold CSS — measured under Playwright emulation, animationPlayState remains running regardless of the preference. Add @media (prefers-reduced-motion: reduce) { .skel-bone::after, .skel-bone-circle::after { animation: none; } } to freeze the shimmer for affected users.
  • No accessibility attributes: no role="status", no aria-busy, no aria-live. Screen readers see ten empty divs without context. For a loading state: set aria-busy="true" on the parent container during the fetch, aria-live="polite" to announce incoming content, and remove or replace .article-skel once data is available.
  • Ghost nodes: the ten bones are empty elements with no text or label. Set aria-hidden="true" on .article-skel to remove them from the accessibility tree and avoid ten keyboard-navigation stops.
  • Deliberately low contrast: the bone base (rgba(255,255,255,.08) on #0a0a0f) gives roughly 1.5:1 — intentionally invisible. No information is encoded in the color; the skeleton is structural and decorative. WCAG 1.4.11 (non-text UI components) does not apply to a loading placeholder. On a light background, switch the base to rgba(0,0,0,.08).

Browser compatibility

The inset: 0 shorthand on the ::after pseudo-element sets the technical floor: Chrome 87, Firefox 87, Safari 14.1, Edge 87 (2020). Everything else — @keyframes, background-size, linear-gradient, border-radius, display: flex — has been available since 2013. Zero dependencies, zero JavaScript.

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

Without inset (pre-2020), the ::after collapses to 0 × 0 px and the shimmer disappears. The bones remain visible as rgba(255,255,255,.08) blocks with no animation — a recognisable, static loading placeholder.

The code

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

index.html — structure
<div class="article-skel">
  <div class="skel-bone article-skel-hero"></div>
  <div class="skel-bone article-skel-title"></div>
  <div class="skel-bone article-skel-title2"></div>
  <div class="skel-bone article-skel-p"></div>
  <!-- … 4 total -->
  <div class="article-skel-author">
    <div class="skel-bone-circle article-skel-author-avatar"></div>
    <div>
      <div class="skel-bone article-skel-author-name"></div>
      <div class="skel-bone article-skel-author-date"></div>
    </div>
  </div>
</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
Card width (CSS — .article-skel { width: 290px }) 290 px Bones expressed in % (article-skel-hero, title lines, body lines) adapt automatically. For an editorial column: width: 100%; max-width: 680px with an explicit hero height.
Hero image height (CSS — .article-skel-hero { height: 130px }) 130 px The visually dominant surface. 80px for a compact list, 200px for a magazine hero, 0 (or display: none) for an article without an image.
Shimmer duration (CSS — animation: 1.8s ease-in-out 0s infinite shimmerSlide) 1.8 s Applies to all bones simultaneously (0 s delay). 1.2s for a faster perceived load; 2.5s for a calmer feel. To stagger bones: .article-skel-title::after { animation-delay: .15s; } (target ::after, not the bone itself).
Shimmer intensity (CSS — rgba(255,255,255,.1) in the ::after gradient) .1 Peak opacity of the highlight. .15 to .2 for a more visible effect on a dark background; .05 to make it nearly invisible. The bone base is at .08 — keep the peak below .3 to stay within skeleton conventions.
Bone radius (CSS — .skel-bone { border-radius: 6px }) 6 px 3px for a strict design; 12px for a rounded mobile app. The hero has its own radius (.article-skel-hero { border-radius: 10px }) and should be adjusted separately.
Title line widths (CSS — .article-skel-title { width: 85% } and .article-skel-title2 { width: 60% }) 85 % and 60 % Simulate a two-level heading or a long title followed by a subtitle. Change to 90/75 for a longer title; remove .article-skel-title2 for a single-line title.
Body line height (CSS — .article-skel-p { height: 9px }) 9 px Roughly half the line height of 16 px body text. 11px for denser content; 7px for small secondary text.

FAQ

Card Skeleton places the avatar at the top (social-media-post layout: author before the image, then image, then three body lines). Article Skeleton opens with the hero image (130 px, full width), continues with two title lines and four tapering body lines, and reserves the author for the end — the reading-view layout of a blog post. The difference is structural, not just ordering: the hero height and the decreasing body-line widths express an editorial hierarchy, not a social content card.
Yes, but carefully. The rules .article-skel-p:nth-child(5/6/7) target children 5, 6 and 7 of .article-skel — not the 2nd, 3rd and 4th paragraph elements. If any element is inserted before the body lines in the card (for example an extra subtitle), the positions shift and the widths land on the wrong bones. For a modified structure, replace the :nth-child selectors with distinct classes (.article-skel-p--95, etc.) or inline styles.
No. .demo-preview (background #0a0a0f, centered flex, min-height: 300px) is the Effect.Labs site's demonstration frame — it is not required for the skeleton to work. The first two CSS blocks in the sold code (.demo-preview, .demo-preview *… and .demo-preview {…}) can be removed at integration. The effect starts at .article-skel and its associated classes.