Scroll Edge

Scrolling content fades out at its edges instead of being cut off by a hard line, like under iOS bars. Each edge appears only when there's more content past it. Pure CSS, on any scrolling element; part of Liquid Blur.

AllAmbientElectronicIndieJazzR&BSoulClassicalFolkRock
  1. Midnight CityM83
  2. HoloceneBon Iver
  3. RetrogradeJames Blake
  4. BreatheTélépopmusik
  5. MythBeach House
  6. NightsFrank Ocean
  7. TeardropMassive Attack
  8. Pink + WhiteFrank Ocean
  9. Svefn-g-englarSigur Rós
  10. Motion Picture SoundtrackRadiohead
On this page

Get started

Scroll Edge is part of the Liquid Blur stylesheet, so there’s nothing else to install. It doesn’t need glass: it works on any scrolling element.

  1. Install Liquid Blur.

    pnpm add @fluidkit/blur
  2. Import the stylesheet once, before your own styles.

    import "@fluidkit/blur/style.css";
  3. Add lb-edge to the scrolling element. No script or extra markup.

    <ol class="songs lb-edge">…</ol>
    
    <style>
      .songs { overflow-y: auto; }
    </style>
  1. Install Liquid Blur and import the stylesheet once in your app’s root.

    pnpm add @fluidkit/blur
    import "@fluidkit/blur/style.css";
  2. Add lb-edge to the scrolling element. No script or component.

    <ul className="list lb-edge">{rows}</ul>

Examples

A list and a row of chips

The list fades at the top and bottom, the chips at the sides. At the start of a scroll there’s no fade on that side; it appears as content goes under the edge. At the end, the last fade disappears, so the last item is never covered.

AllAmbientElectronicIndieJazzR&BSoulClassicalFolkRock
  1. Midnight CityM83
  2. HoloceneBon Iver
  3. RetrogradeJames Blake
  4. BreatheTélépopmusik
  5. MythBeach House
  6. NightsFrank Ocean
  7. TeardropMassive Attack
  8. Pink + WhiteFrank Ocean
  9. Svefn-g-englarSigur Rós
  10. Motion Picture SoundtrackRadiohead
<div class="lb card">
  <div class="chips lb-edge-x">…</div>
  <ol class="songs lb-edge">…</ol>
</div>
.songs { overflow-y: auto; overscroll-behavior: contain; }
.chips { overflow-x: auto; --lb-edge-size: 20px; }

Under a sheet title

The list in Drag’s sheet uses lb-edge: rows fade out under the title as they scroll, and the first row isn’t faded at the top.

Options

Class or variable Description
lb-edge Fades the top and bottom, for vertical scrolling
lb-edge-x Fades the left and right, for horizontal scrolling
--lb-edge-size Length of the fade, and how much scrolling it takes to appear. Default: 28px. Inherited
--lb-edge-start, --lb-edge-end The same for one side: top (or left) and bottom (or right). Default: --lb-edge-size. 0px turns that side off
--lb-edge-strength How transparent content gets at the edge. Default: 1 (fully); 0.5 is half
/* A chat: newest messages at the bottom, so only the top fades, and further */
.messages { --lb-edge-start: 48px; --lb-edge-end: 0px; }

/* Keep text slightly readable under the edge */
.notes { --lb-edge-strength: 0.6; }

How it works

A mask

The fade is a mask on the scrolling element: content goes from opaque to transparent right at the edge. Since it fades rather than paints over, it works on glass, photos and plain backgrounds alike.

Driven by scroll

Each fade is as long as the content hidden past that edge, up to --lb-edge-size. It grows as content scrolls under the edge and shrinks to nothing at the end. Scroll-driven animations handle this, momentum included, with no script. If there’s nothing to scroll, there’s no fade.

Put it on the scrolling element, not on glass itself (it would fade the glass too). For example, on a list inside the glass. It uses the element’s mask and animation, so your own values for those would override it.

Browser support

Any browser with scroll-driven animations and @property: Chrome and Edge 115, Safari 26. Elsewhere (Firefox) there’s simply no fade.

Limitations

  • The scrolling element’s own mask and animation are replaced.
PlaygroundIts hard cases, live: slowed down, on other backdrops, with their boxes drawn.