revealOnScroll
Reveals elements as they enter the viewport — an observer marks, CSS animates.
Scroll this page. Every card below fades and rises into place the moment it enters the viewport — and stays there. The script only ever marks what the browser reports as out of sight, so nothing you can already see is taken away; the six examples add a stagger, a selector instead of a marker per item, the four directions, a late trigger line, the single-element lane and a reveal that replays inside its own scroll box.
1 — Marked items, default look
The section carries data-js-behavior="revealOnScroll",
each element to be revealed carries data-reveal-item,
and the look comes from .c-reveal. Three items, three
reveals — the heading included.
This card was transparent and 32px lower a moment ago. The
distance is --reveal-distance, the timing
--reveal-duration / --reveal-ease — all
declared on .c-reveal itself, so a single item can be
retuned with an inline custom property.
Reveal-once is the default: the attribute is gone, the item is unobserved, and when the last item of an instance is done both of its observers are disconnected. Scrolling back up leaves everything in place.
2 — A selector instead of a marker, and a stagger
The cards below carry no data-reveal-item:
data-reveal-items=":scope > li" names
them from the container instead — the lane for markup you cannot
edit, a CMS list or a generated grid. With
data-reveal-stagger="90" the four of them are
released 90ms apart, in document order, so the grid arrives as a
sequence. A reader who asked for reduced motion gets no sequence
and no reveal at all: the content is simply there.
- First
- Second
- Third
- Fourth
3 — The four directions
One instance, four modifiers of the same component:
--fade does not move at all (for a box that must not
shift), --left and --right slide in
sideways, --zoom grows into place. Each of them sets
exactly one custom property, so a fifth direction is one
declaration on the item — no new modifier needed.
--fade — opacity only
--zoom — from 0.94
--left — from the inline start
--right — from the inline end
4 — A later trigger line
data-reveal-offset="200" moves the trigger line 200px
above the bottom edge of the viewport: the panel is not revealed
when its first pixel appears but once it has come that far in.
Useful for a tall element whose top edge would otherwise arrive
long before the reader is looking at it.
Watch the bottom edge of the window as this panel comes up: it stays transparent for 200 more pixels of scrolling, then travels its 64px into place. The offset is also what keeps the repeat lane honest — an item that stops crossing the line is only hidden again once it is completely out of sight, never while it is still visible below the line.
5 — The single-element lane
The blockquote below has no marked item inside it, so the container is the item itself: one attribute on one element, and no wrapper to write. It is the same code path as everywhere else — the fallback is in the item lookup, not in a second mode.
“Pick the least powerful language that does the job.” The watching is the browser's (IntersectionObserver), the animating is the stylesheet's, and what is left for the script is one attribute per item.
6 — Inside a scroll box, replaying
The items below scroll inside the framed overflow: auto
box — and there is no root option to set: an
observer on the default root intersects an item with the clip box
of every ancestor, so the box is the browser's business, not the
module's. data-reveal-repeat puts an item back into
its waiting state once it has left the view, so scroll the
box up and down and the reveal replays as often as you
like. Tab into it as well: the keyboard reveals an item before the
scrolling does, and whatever holds the focus is never hidden
again.
First item in the box. A link so there is something to tab to.
Second item. What decides here is whether the box shows it and the box itself is on screen — both are one intersection to the browser.
Third item. Another link — tab past the fold and watch it arrive before it is scrolled to.
Fourth item, and the one that shows the stagger inside the box: 60ms apart, in document order.
Fifth item. Scroll back to the top of the box and down again —
every one of these replays, because the container carries
data-reveal-repeat.