027

Page Preloader

£7 or the whole Vault, £79.20

A complete load sequence: a counter climbs to 100 behind a full-screen overlay, the overlay clears with one of four exit styles (curtain wipe, split doors, iris, or fade), and the page content staggers in behind it.

intermediate
4 more details
load-sequencecount-uppage-transitionstagger

This demo reads better at your own screen size than in the frame below:

Updated

About this effect

A full page-load sequence built on GSAP core alone, with no plugins required. A fixed overlay carries a brand mark, a tabular-figure counter that climbs to 100, and a thin progress bar; when the count completes, the overlay chrome lifts away, twin curtain panels wipe upward, the back one a step lighter so the swipe reads as two tones, and every element you mark as a reveal target staggers into place behind the clearing curtain. One attribute swaps that default wipe for split doors, an iris opening from the centre, or a quick clean fade.

Read the full effect overview

The counter can be pure theatre on a fixed duration, or hold at 90 until the browser's load event so it reflects real asset loading. A once-per-session mode skips the sequence for returning visitors, and a preloader:complete event lets you chain your own animations off the end of the exit.

Everything is driven by data attributes on the overlay element, and the whole thing degrades cleanly: without JavaScript the overlay never renders and the page is a plain document.

Page Preloader - GSAP animation effect preview

What's included

8 items
  • Counter with tabular figures and progress bar synced to one proxy value, never drifting apart
  • Four exit styles on one attribute: two-tone curtain wipe, split doors, iris opening from the centre, or a clean fade
  • Staggered entrance for any element marked data-preloader-reveal, timed to the clearing curtain
  • Wait mode holds at 90 until the window load event, so the number reflects real loading
  • Once-per-session mode via sessionStorage so repeat visitors skip straight to the page
  • preloader:complete event on document for chaining hero animations or analytics
  • Scroll locked while the overlay is up, released the moment the curtain clears
  • No plugins: GSAP core only, and a plain readable page when JavaScript is off

Perfect for

5 use cases
  • Portfolio and studio sites that open with a branded moment instead of a paint flash
  • Image-heavy landing pages using wait mode to cover real asset loading
  • Campaign and product-launch pages where the reveal is part of the pitch
  • Agency sites chaining hero type animations off the preloader:complete event
  • Any site swapping a spinner for a designed, skippable load sequence

How it works

3 sections

One value climbs from 0 to 100 and writes both the padded counter text and the bar's width, which is why the number and the bar can never disagree. In wait mode it holds at 90 until the page has actually finished loading, then sprints to 100.

Completion hands off to an exit timeline: overlay chrome fades up and out with a stagger, the two curtain panels wipe upward offset by a fraction of a second, and the reveal targets animate in on a stagger that starts before the curtain has fully cleared. The script adds a has-js class to the html element before first paint; all hiding CSS is gated behind it, so no JavaScript means no overlay and no hidden content, and reduced-motion visitors take the same skip path.

A data-preloader-exit attribute swaps the middle of that exit timeline: split slides the panels out sideways in opposite directions like parting doors, iris opens a growing circular hole in the panels so the reveal reads as an expanding ring, and fade takes the whole overlay out with a slight scale-up. Every style ends the same way, with the overlay set to display none, the scroll lock released, and preloader:complete dispatched.

Difficulty Intermediate
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this effect's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Paid effect

Purchase to unlock the code.

Buying Page Preloader opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£7 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £79.20, one payment.

Documentation

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

2. Add the overlay as the FIRST thing inside <body>:

Code snippet omitted: it ships with the download.

3. Mark the elements that should stagger in after the curtain clears:

Code snippet omitted: it ships with the download.

4. Add before closing </body> tag:

Code snippet omitted: it ships with the download.

Using It With Your Own Design

What the effect needs from your markup is small: one overlay element carrying data-preloader as the first child of <body>, and inside it whatever you want to fade (data-preloader-fade), the counter (data-preloader-count), the bar fill (data-preloader-bar) and one or two panels (data-preloader-panel). Anything in the page marked data-preloader-reveal staggers in as the curtain clears. The script never reads a class name, so the preloader__* classes are only there to hang styles on.

The stylesheet has a handful of rules the sequence depends on, each marked CONTRACT in style.css; keep them when you restyle:

  • .preloader { display: none } with .has-js .preloader { display: block }: the overlay only exists when the script runs, so a page without JavaScript is a plain document.
  • .has-js [data-preloader-reveal] { opacity: 0; visibility: hidden; transform: translateY(28px) }: the reveal start state. Change the distance freely; without the pre-hide the reveal paints visible, flashes to 0 and fades back in.
  • The panels are position: absolute; inset: 0 inside the fixed overlay, stacked in DOM order. The script moves them and never sets their colour, so the front and back panels are yours to colour. The back panel is what shows behind the front one during the wipe and around the iris hole, so give it a visible step from the front.
  • The iris rule keyed on [data-preloader-exit="iris"]: a radial-gradient mask on each panel driven by the --iris variable the script tweens. Delete it only if you never use the iris style.
  • .preloader-lock { overflow: hidden } on <html>: the scroll lock while the overlay is up.
  • The bar fill needs transform-origin: left center (or wherever you want it to grow from); the script only sets scaleX.

Everything else, the landing hero, the nav, the segmented exit switcher, the photograph, the counter's size and face, is the demo's own design and can be deleted or restyled. Tabular figures on the counter (font-variant-numeric: tabular-nums) stop the number jittering sideways as digits change, which any face benefits from.

Options

All options go on the data-preloader overlay element.

Attribute Values Default Description
data-preloader-duration Seconds 2.4 How long the counter takes to reach 100 (or 90 in wait mode)
data-preloader-once true, false false When true, the sequence runs once per browser session; repeat visitors skip straight to the page
data-preloader-wait true, false false When true, the counter holds at 90 until the window load event fires, then sprints to 100 — the number reflects real asset loading
data-preloader-exit wipe, split, iris, fade wipe Exit animation. wipe: twin panels wipe upward, front first, back chasing. split: the panels part sideways like doors, front sliding out left with the back chasing out right. iris: a circular opening grows from the centre of the screen. fade: the overlay fades out with a slight scale-up, quick and clean

Element Hooks

Attribute Where Description
data-preloader The overlay The root of the sequence; options live here
data-preloader-panel Inside overlay Curtain panels. They wipe upward in DOM order: first panel lifts first, second chases it. One panel also works
data-preloader-count Inside overlay Receives the padded counter text (000 to 100)
data-preloader-bar Inside overlay Scaled from scaleX(0) to scaleX(1) in sync with the counter
data-preloader-fade Inside overlay Overlay chrome (brand, count, bar) that lifts away before the curtain wipes
data-preloader-reveal Anywhere in the page Staggers in (rise + fade) as the overlay clears
data-preloader-replay Any <button> Optional: clears the once-per-session flag and reloads the page to run the sequence again
data-preloader-exit-override On a replay button Optional: an exit style (wipe, split, iris, fade) to run on that reload. The click stores it in sessionStorage; on the next load the script reads and clears it, and it wins over data-preloader-exit for that one run

The iris style needs no extra markup: the script writes the resolved exit style back onto the overlay's data-preloader-exit attribute, and the stylesheet's iris rule (a radial-gradient mask driven by a --iris variable, applied per panel) keys off it. The panels open in sequence, front first and back chasing, so the hole's edge is always the back panel's colour against your page and the opening reads as an expanding ring. An overlay built without panels irises as one piece instead.

Zero-Flash Setup (recommended)

The script adds a has-js class to <html> as its first statement, and all hiding CSS (.has-js .preloader, .has-js [data-preloader-reveal]) is gated behind it. Because the script loads at the end of <body>, an extremely slow connection could paint the page for a moment before it runs. To guarantee a zero-flash start, move that one line into your <head>:

Code snippet omitted: it ships with the download.

The line at the top of script.js is harmless to leave in place; adding a class twice does nothing.

Accessibility

  • Reduced motion: with prefers-reduced-motion: reduce the sequence never runs — the overlay is hidden and content is simply there. This is enforced twice: in CSS via the media query and in JavaScript via gsap.matchMedia.
  • No JavaScript: the overlay is display: none by default and reveal targets are only pre-hidden when the has-js class is present, so the page renders as a plain readable document.
  • Screen readers: the counter is aria-hidden (a number flashing to 100 is noise); a visually hidden role="status" element announces "Loading page" instead.
  • Scroll lock: scrolling is disabled only while the overlay is up and always released, including on the skip paths.

Dependencies

Required:

  • GSAP 3.12+ (core only — no plugins)

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.