Scroll Fade

Fades the edges of a scroll container, and only while there is content to reveal in that direction.

scroll-fade masks the edges of any scroll container so content dissolves instead of being cut off. Where the browser supports scroll-driven animations, each edge only fades while there is something to reveal in that direction: the top edge is sharp when you are at the top, and fades in as you scroll away from it. No JavaScript is involved.

It is a plain utility — it needs no component, and works on anything that scrolls.

<div class="h-56 overflow-y-auto scroll-fade">
  <!-- both edges fade as you scroll -->
</div>

Examples

Edges

scroll-fade fades both block edges. Narrow it to one edge when only one of them ever needs it — a chat transcript typically fades the bottom only.

ClassFades
scroll-fadeboth block edges (alias of scroll-fade-y)
scroll-fade-ytop and bottom
scroll-fade-xboth inline edges
scroll-fade-ttop
scroll-fade-bbottom
scroll-fade-sinline start (flips under dir="rtl")
scroll-fade-einline end (flips under dir="rtl")
scroll-fade-lleft, physical
scroll-fade-rright, physical
scroll-fade-noneremoves the mask
Preview
Code
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15
Row 16
Row 17
Row 18
Row 19
Row 20
Row 21
Row 22
Row 23
Row 24
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15
Row 16
Row 17
Row 18
Row 19
Row 20
Row 21
Row 22
Row 23
Row 24
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15
Row 16
Row 17
Row 18
Row 19
Row 20
Row 21
Row 22
Row 23
Row 24

Size

The fade defaults to min(12%, 2.5rem). Set it globally with scroll-fade-<n> or per edge with scroll-fade-<edge>-<n>, where n is a spacing step; arbitrary values work too.

ClassSize
scroll-fade-16every edge, 4rem
scroll-fade-b-16bottom edge, 4rem
scroll-fade-b-[4rem]bottom edge, arbitrary value
Preview
Code
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15
Row 16
Row 17
Row 18
Row 19
Row 20
Row 21
Row 22
Row 23
Row 24
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15
Row 16
Row 17
Row 18
Row 19
Row 20
Row 21
Row 22
Row 23
Row 24
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15
Row 16
Row 17
Row 18
Row 19
Row 20
Row 21
Row 22
Row 23
Row 24

Horizontal

scroll-fade-x fades both inline edges of a horizontal scroller — a filter row, a tag strip, a carousel. The logical variants (-s, -e) follow the writing direction, so they swap sides under dir="rtl".

Preview
Code
tag-1
tag-2
tag-3
tag-4
tag-5
tag-6
tag-7
tag-8
tag-9
tag-10
tag-11
tag-12
tag-13
tag-14
tag-15
tag-16
tag-17
tag-18
tag-19
tag-20
tag-1
tag-2
tag-3
tag-4
tag-5
tag-6
tag-7
tag-8
tag-9
tag-10
tag-11
tag-12
tag-13
tag-14
tag-15
tag-16
tag-17
tag-18
tag-19
tag-20

How it works

The utility sets a CSS mask built from custom properties, and drives those properties with a scroll-linked animation:

animation-timeline: scroll(self y);
animation-range: calc(100% - var(--scroll-fade-reveal)) 100%;

Two things follow from that.

The reveal distance — how much scrolling it takes for an edge to reach full fade — is --scroll-fade-reveal, 6rem by default. Override it, or the fade size, per element:

<div class="overflow-y-auto scroll-fade" style="--scroll-fade-reveal: 2rem">

Scrollbars

The scrollbar utilities pair with scroll-fade and are documented on their own page: scrollbar.