Skip to the content

Print table

A gallery that starts as a pile. The photographs lie on a dark table the way a hand let them go: in small handfuls, each at its own angle, one over the other, a couple slid half out of the pile, none fully hidden, with a soft contact shadow.

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

    The grid belongs to the page: its columns, rows, gaps and spans are yours to write on the table, and the tidy state is that layout to the pixel. Three things the stylesheet cannot do for you: pinned, the grid has to fit one screen, so size its rows from the height left or set data-print-table-hold="off"; no parent of the section may cut its overflow with overflow: hidden, which stops the block from pinning, so use overflow-x: clip; and a print must not clip its own overflow, or it loses its shadow.
  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-print-table Marks the section the page scrolls through while the prints are tidied. It takes no value: leave the value field empty. That section is what the stylesheet makes taller by the scroll the tidying takes, and what carries the settings. Without it on any element of the page, the embed marks the section holding the table.
    data-print-table-pin Marks the block that stays on screen, a child of the section, holding the table and whatever stays with it. It takes no value. Without it the engine takes the child of the section that holds the table. [ Optional ]
    data-print-table-surface Marks the table: the grid the prints are squared up into, and the frame they are kept in while loose. It takes no value. Its columns, gaps and spans are the page's own. Without it the engine takes the parent of the first marked print, and with neither mark nothing is mounted and the console says so. [ Optional ]
    data-print-table-print Marks one print, a direct child of the table. It takes no value. A print can be a link: a plain click still opens it, a drag never does. Without it on any of them, the engine takes the table's own children as the prints. [ Optional ]
    data-print-table-state Written by the engine on the section: pin while the block holds the screen, flow when hold is off, still under reduced motion. Never written by hand; it is what the stylesheet reads to pin the block and to give the prints their shadows. [ Optional ]
    data-print-table-tidy Written by the engine on the section while the grid is done, and taken off when a print leaves its cell. Never written by hand. [ Optional ]
    data-print-table-grab Written by the engine on the section when prints can be taken. Never written by hand; the stylesheet reads it for the open hand. [ Optional ]
    data-print-table-dragging Written by the engine on the section while a print is held. Never written by hand; the stylesheet reads it for the closed hand. [ Optional ]
    data-print-table-held Written by the engine on the print in the hand. Never written by hand; a rule of your own can read it. [ 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-print-table-shadow #000000 Colour of the shadow a print casts, on the table and on the prints under it. Options: any CSS colour. Black on a dark table; on a light table a dark tone of the table's own colour reads softer than black.
    data-print-table-scatter 0.7 How far apart the prints are thrown, from 0 to 1.
    data-print-table-seed 21 Which throw it is, a whole number. The same number on the same table gives the same pile, on every load. Options: any whole number, each one another pile. Try a few and keep the one that suits the pictures.
    data-print-table-rotation 16 Widest angle a thrown print lies at, in degrees.
    data-print-table-length clamp(900px, 170vh, 2400px) Scroll the tidying takes, any CSS length: how long the block holds the screen. Only read when hold is on.
    data-print-table-hold on Whether the block holds the screen while the prints are tidied: on or off. Options: on pins the block for length of scroll, right for a grid that fits one screen; off leaves the section in the flow and tidies the prints while the table rises through the window, right for a grid taller than the screen.
    data-print-table-start 0.1 Point of the scroll where the tidying starts, as a share from 0 to 1. Pinned, a share of length; not pinned, a share of the way the top of the table makes from the foot of the window to its top.
    data-print-table-end 0.8 Point of the same scroll where the grid is done, from 0 to 1.
    data-print-table-stagger 0.5 Head start of the first print on the last, from 0 to 1.
    data-print-table-overshoot 0.04 How far a print slides past its cell before settling, as a share of its way, from 0 to 0.3. Its angle swings past square by twice that.
    data-print-table-smooth 0.2 Time the prints take to catch the scroll, in seconds.
    data-print-table-drag on Whether a print can be picked up and thrown: on or off. Options: on lets the mouse, a pen or a finger take a print; off leaves the scroll as the only hand, and the prints plain links.
    data-print-table-friction 0.07 Share of its speed a thrown print loses at each frame, from 0 to 1.
    data-print-table-lift 1.06 Scale of a print held in the hand, 1 being its size on the table.

What it does

Print table is a scroll animation for Webflow and vanilla JavaScript, with no library. Also called scattered images to grid on scroll, scatter to grid gallery or photo pile gallery.

A gallery that starts as a pile. The photographs lie on a dark table the way a hand let them go: in small handfuls, each at its own angle, one over the other, a couple slid half out of the pile, none fully hidden, with a soft contact shadow. The section holds the screen while the page scrolls, and the scroll tidies them: each print slides to its cell on its own timing, the bottom of the pile first, along a slightly bent path, turns straight, runs a hair past its place and settles, like a hand squaring a stack. Scrolling back throws them where they were. Any print can be picked up, with the mouse, a pen or a finger: it rises, its shadow lengthens, it trails behind the hand and leans with its speed, comes to the top of the pile, and when thrown slides with friction and stops where it stops, kept on the table. A press that does not travel is a click, so a print stays a link. The grid is not the component's: it is a real CSS grid the page styles, columns, gaps and spans, and the engine reads the cells where the layout put them and animates between the pile and them with transforms only, so the tidy state is that layout to the pixel at every breakpoint, with no inline style left on it. Without the script, and under reduced motion, the page is the grid. No library: the hold is sticky positioning, the pile is seeded so it is the same on every load and thrown again for the size of the screen. Pattern type scattered gallery, photo pile to grid, contact sheet.

Updated

Questions

Mark a section data-print-table, the block that stays on screen data-print-table-pin, your grid data-print-table-surface and each of its direct children data-print-table-print. The grid stays a plain CSS grid of your own, columns, gaps and spans: the engine reads where the layout put each print and animates from the pile to there with transforms only. data-print-table-length is the scroll the tidying takes.

None of them: no library is loaded. The hold is sticky positioning, each print eases to its cell on its own timing and runs a hair past it, data-print-table-overshoot, and a thrown print slows with a friction the engine computes. In its cell a print carries no inline style at all.

Yes, the pile is seeded: data-print-table-seed picks the throw, and the same number gives the same pile. data-print-table-scatter, 0.7 by default, is how far apart the prints are thrown, and data-print-table-rotation, 16 degrees by default, the widest angle a print lies at. No print is ever fully hidden under the others.

Yes to both. A print is picked up by pressing and moving: it rises, trails behind the hand and leans with its speed, then slides and stops where it was thrown, kept on the table. A press that travels less than six pixels opens the print's link and a drag never does. data-print-table-drag="off" turns the hand off.

Set data-print-table-hold="off". The section then stays in the flow instead of holding the screen: the pile is thrown over the whole table and tidied while the table rises through the window. Without the script, and under reduced motion, the page is simply the grid.