Skip to the content

Gravity footer

Small objects drop into a footer one at a time, stack up wherever they land against its floor and its two sides, and can be picked up and thrown with a mouse or a finger.

Become a member to unlock the full effect today.

Join now

Already a member? Sign in

Documentation

  1. Copy to Webflow

    Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: Webflow removes any font your site has not installed.

  2. Add custom CSS

    Two things belong to the page rather than to the component. The objects need somewhere to gather: they stack against the bottom of the footer, so a footer whose content runs all the way down leaves them nowhere to be seen except behind the text. Keep a band of padding at the bottom, as the paste does, and the heap has a floor of its own. And the objects take their colours from the page: --gravity-footer-accent first, then the page’s own --accent, then the ink #15100c, with --gravity-footer-panel and --gravity-footer-ink doing the same for their body and their marks. They are read when the pile is built, so a variable that lands later is not seen until the next play.
  3. Add custom JS

  4. Tune it

    Custom attributes
    Select the section on the canvas and open the Settings panel. Under Custom attributes, add a pair: the name on the left, the value on the right.
    Custom attributeWhat it does
    data-gravity-footer Goes on the footer section and takes no value. It marks the element the objects fall into: they stack up against its floor and its two sides, and the footer’s own content stays in front of them, untouched.
    data-gravity-footer-state Written by the engine on the footer while the objects are coming down, and taken off once the heap is at rest. Never written by hand, and a page can style on it. [ Optional ]
    data-gravity-footer-pile Written by the engine on the footer while the effect is mounted, and removed by destroy(). The stylesheet makes the footer a stacking context of its own on it, and that is what makes the objects visible at all: without it the footer’s own background paints over every one of them, while the pile runs, sleeps and reports itself perfectly. Never written by hand. [ Optional ]
    data-gravity-footer-canvas Written by the engine on the canvas it lays inside the footer, and removed with it. The stylesheet fills the footer with that canvas and paints it over the footer’s background but behind every one of its blocks, so a link is never covered by an object. It takes no pointer event, so a click always reaches what is under it. Never written by hand. [ Optional ]
    data-gravity-footer-grab Written by the engine on the footer while objects can be picked up, so the stylesheet can hand every vertical gesture back to the browser with touch-action. It is the mark, not the grab setting below, and the two are spelled apart on purpose: a mark carries no value and a setting is read by its value. Never written by hand. [ Optional ]
    data-gravity-footer-debug-pieces, data-gravity-footer-debug-seconds, data-gravity-footer-debug-trigger Written by the engine on the footer at the end of a run, and only while the debug setting below is on: how many objects fell, how long the run took, and what set it off. They are there to read a preview that cannot be inspected. Never written by hand. [ Optional ]
    Settings
    Every setting is a custom attribute too, added the same way and on the same section. An attribute always wins over the defaults written in the code.
    AttributeDefaultWhat it is
    data-gravity-footer-fill 0.11 How much of the footer's area the objects cover altogether, which is what sets how many there are.
    data-gravity-footer-size 0.11 How wide one object is, as a share of the footer's shorter side.
    data-gravity-footer-pull 1100 What pulls a falling object down, in pixels per second squared. This is the speed of the whole effect: it decides how long an object is in the air and so whether the fall can be read at all.
    data-gravity-footer-spawn 0.12 The time between two objects arriving, in seconds. A little unevenness is added to it, so a row of arrivals does not read as a machine pouring things out.
    data-gravity-footer-rebound 0.42 How much of its speed an object keeps off a wall or off another object.
    data-gravity-footer-grip 0.2 How much two objects and the floor hold on to each other.
    data-gravity-footer-grab true Whether objects can be picked up and thrown. Options: false, they are only ever looked at, true.
    data-gravity-footer-look impact How an object arrives and how its landing is shown. Drawing only: the physics is identical under all four. Options: raw (nothing added, the bare simulation), arrive (it fades and grows into its first fall), impact (arrive, plus a brief squash against the side it hit and a glint on that edge), ripple (arrive, plus a short wave leaving the point it touched).
    data-gravity-footer-delay 0 The wait before the first object arrives, in seconds.
    data-gravity-footer-trigger 0.9 How far into the screen the footer has to come before it plays, as a share of the viewport height.
    data-gravity-footer-replay false Whether it plays again every time the footer comes back into view. Options: false (once), true (every entry).
    data-gravity-footer-debug false Whether the last run is written on the footer as data-gravity-footer-debug-* attributes: objects, seconds, trigger. Options: false, true. For reading a preview that cannot be inspected.
    Local time
    The clock in the third column is not part of the effect: a short script at the end of the Embed keeps it running. Select the clock (named Local time in the Navigator), open the Settings panel, and change its two custom attributes. The word Local time above it is ordinary text. To drop the clock, delete its column and the script at the end of the Embed.
    Custom attributeWhat it does
    data-footer-zone The time zone the clock shows, written like Europe/Paris or America/New_York. Empty, it shows the visitor's own time.
    data-footer-hours Opening hours, from and to, like 9-17. The order desk line and the dot say open or closed from them, Monday to Friday.

What it does

Gravity footer is an animated navigation component for Webflow and vanilla JavaScript, built on Matter.js 0.20.0. Also called falling objects footer or physics footer.

Small objects drop into a footer one at a time, stack up wherever they land against its floor and its two sides, and can be picked up and thrown with a mouse or a finger. The footer's own links sit in front of them, readable and clickable, and the page never loses its scroll. It stops dead when everything is still: no frame is drawn at rest. No build step and no image file; the objects are drawn with canvas calls alone. Nothing is measured or written at rest, and with no JavaScript, with reduced motion, or if the library never arrives, the footer is simply there.

Updated

Questions

Select the footer, open the Settings panel, and under Custom attributes add data-gravity-footer with an empty value. Settings go on that same element as more attributes, for instance data-gravity-footer-fill="0.18". Nothing depends on a class, so restyling the footer cannot break the effect.

Matter.js 0.20.0, under the MIT licence, loaded from one pinned CDN script tag. Matter's own renderer and its MouseConstraint are not used: the objects are drawn on one canvas and the drag is written on pointer events. Without the tag the footer is left as it is and says so once in the console.

There is no object count: set data-gravity-footer-fill, the share of the footer's area the objects cover, 0.11 by default. Lower gives a handful scattered along the floor, higher a deep heap that climbs the footer. data-gravity-footer-size, also 0.11, is the width of one object as a share of the footer's shorter side.

Yes. The objects live on a canvas behind the content, marked aria-hidden and never in the tab order, and a press that lands on a link, a button or a field is always left to that element. The text stays selectable and the reading order never changes.

No. With a finger, a sideways drag picks an object up and a vertical gesture always scrolls the page, because the component sets touch-action: pan-y pinch-zoom and registers no wheel listener. Do not put a touch-action of your own on the footer, and write data-gravity-footer-grab="false" if the objects should only be looked at.