056

Poster Grid Template

£20 or the whole Vault, £99

A one-page site for a poster biennale, built on a twelve-column rule grid that is printed on the page rather than hidden behind it: the grid draws itself in as measured rules while the headline sets column by column, four photographic plates reflow between fixed compositions with GSAP Flip, and a marginalia rail down the outer column tracks scroll on three channels at once.

ScrollTriggerFlip Lenis intermediate
13 more details
grid-drawscroll-revealscrubparallaxflip-layouttext-animationstaggercount-upscroll-progressclick-toggleduotoneprogressive-enhancementkeyboard-navigation

This template reads better at your own screen size than in the frame below:

Updated

About this template

A production-ready one-page site for a poster biennale, print studio, type foundry or design festival. It ships as a finished site for a fictional event, The Measure, the ninth Leeds Poster Biennale: an open call, a programme of press days and talks, four selected plates and a colophon, all written in the voice of a small organisation that runs a press six days a week.

Read the full template overview

The design idea is that the grid is visible. A twelve-column rule grid is drawn on the page as a design element and every headline, label and plate is set to it, at roughly ten times the scale contrast between the display line and the smallest dimension label. The palette is three colours and nothing else: warm paper, printing ink and one ink-red, used the way a two-colour press would use them.

Three interactions carry the page and none of them repeats another. The grid draws itself in as measured rules while the headline sets a word at a time; a field of four photographic plates reflows between four fixed compositions with GSAP Flip when you choose a plate; and a marginalia rail in the outer column reads scroll position on three separate channels.

Make it yours by repainting three hex values and their RGB triples in the token block, swapping the photographs in assets/img, and rewriting the copy. Every section is found by a data attribute and separately guarded, so you can delete the programme band, the plate field or the type specimen and the rest keeps running.

Poster Grid Template - website template preview

What's included

10 items
  • A visible twelve-column rule grid that draws itself in from the margins on load, with the dimension labels ticking up to their printed values like a spec drawing filling in
  • A display headline that sets itself column by column, each word snapping in from its own column rather than fading
  • One full-bleed duotone plate that breaks three columns and runs off the edge of the sheet, with a solid ink caption strip
  • A plate field where four photographs reflow between four fixed twelve-column compositions with GSAP Flip, the field's horizontal rules travelling to match on the same curve
  • A marginalia rail down the outer column reading scroll on three channels: the section numeral, a measured rule with a millimetre readout, and Cardo side-notes that swap with a short overshoot
  • An inverted full-bleed programme band setting the schedule as type rather than as cards
  • A type specimen section built on a single oversized letterform that overruns the left margin
  • Three colours and two Google faces, with every translucent value mixed from an RGB triple so a reskin is a six-value edit
  • Measured contrast throughout, including a documented ban on the red carrying reading-size text
  • A complete no-JavaScript document, a designed reduced-motion state, and keyboard parity on every plate control

Perfect for

6 use cases
  • Design biennales, poster festivals and open calls that need a submission deadline front and centre
  • Print studios, letterpress and risograph shops selling work by the sheet
  • Type foundries and specimen sites where the grid and the scale ladder are the product
  • Editorial, publication and zine launches that want print logic rather than page logic
  • Galleries and exhibition programmes with a dated schedule and a plate list
  • Any portfolio that wants a Swiss, rule-led identity instead of a card grid

How it works

5 sections

Structure

One script initialises each section with a single setup and teardown path, with one motion branch for motion preference and for the 1100px breakpoint where the rail changes axis. Every init takes its section's root element and returns early if the markup is absent, so deleting a section from index.html cannot break the rest. Event listeners are kept together and removed by the cleanup function the responsive branch returns.

The grid draw-in

On load, one timeline runs four things off the same clock: the twelve column rules scale up from the top margin, staggered from the edges inwards; the dimension labels tick from zero to their printed values; each headline word is set visible in a single frame and slid in from one column's width away, so it snaps into place rather than fading; and the supporting copy fades under it. Scrolling the hero then adds a scrubbed channel, softening the rules and drifting the plate against the type.

The plate reflow

Four fixed compositions live in CSS as grid-column and grid-row rules under a data-arrangement attribute on the field. Choosing a plate, or one of the composition numbers, records the state with Flip.getState, swaps the attribute and lets Flip.from animate every plate from where it was to where the new composition puts it. Flip would otherwise collapse the field's height mid-tween, so the taller of the two heights is held for the duration and cleared at the end; the field's horizontal rules are tweened between their old and new offsets on the same curve.

The marginalia rail

A single document-length ScrollTrigger paints three channels from one progress value: the measured rule fills, the millimetre readout counts toward the sheet height, and the tick marks ink over one at a time as they are passed. A second set of triggers, one per section, swaps the section numeral and its Cardo side-note with a short overshoot so each change settles rather than snaps. The notes are read from data attributes on the sections themselves, so a deleted section takes its note with it.

Without JavaScript, and with reduced motion

A synchronous script in the head adds a has-js class before first paint, which is what gates the animation start states; the main script removes it again if the GSAP CDN is blocked, so the page falls back to a plain, fully readable document with the grid already drawn. Under prefers-reduced-motion a CSS block restores every gated element and the script's own motion branch sets the page to its finished state: the rules drawn, the headline set, the plates in the first composition, and the rail still reporting position without any easing.

Plugins ScrollTrigger, Flip
Difficulty Intermediate
Smooth scroll Lenis integration
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this template's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Questions about this template

Why is the grid visible?

Because it is the design. A twelve-column rule grid is printed on the page rather than hidden behind it, drawing itself in from the margins on load while the dimension labels tick up to their printed values like a spec drawing filling in. It is print logic applied to a page, which is the point for a design audience.

What does the plate reflow do?

Four photographs move between four fixed twelve-column compositions with GSAP Flip, and the field's horizontal rules travel to match on the same curve. It is composition as the interaction rather than a carousel, and every plate control has keyboard parity.

How many photographs do I need?

Five or so: four for the reflowing plate field and one full-bleed duotone that breaks three columns and runs off the sheet. The type specimen section is built on a single oversized letterform, and the programme band sets the schedule as type, so neither needs images.

Can I use it for something other than a poster festival?

Yes. Print studios and risograph shops selling work by the sheet, type foundries showing specimens, zine and publication launches, and gallery programmes with a dated schedule all fit. Any portfolio wanting a Swiss rule-led identity instead of a card grid works.

How much of a reskin is it?

Six values. Three colours and two Google faces, with every translucent value mixed from an RGB triple. Contrast is measured throughout, including a documented ban on the red carrying reading-size text, so a repalette has a stated boundary rather than a guess.

Can artists submit work through the entry form?

No. It takes a name, an email, a sheet size and a note about the plate, and confirms on the page, but there is no backend behind it. An open call also needs somewhere to put files, so point it at a form handler that accepts uploads, or at Submittable, which is what most biennales already run.

Paid template

Purchase to unlock the code.

Buying Poster Grid Template opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£20 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £99, one payment.

Documentation

Quick Start

  1. Upload the folder to any static host. index.html is the site.
  2. Replace the copy in index.html with your own.
  3. Drop your photographs into assets/img/ using the same filenames.
  4. Repaint the six values at the top of assets/style.css (see Palette).

The GSAP and Lenis CDN tags at the bottom of index.html are plain script tags with no integrity attributes, so you can self-host the libraries by changing the src values and nothing else.

Code snippet omitted: it ships with the download.

Sections and Options

Every section is found by a data- attribute and initialised on its own. If the attribute is not in the document, the script skips that section silently, so you can delete any section and the rest keeps working.

The grid and hero — data-hero

The twelve column rules are twelve <span class="rule-v"> elements inside .rules. Want eight columns instead of twelve? Change grid-template-columns: repeat(12, 1fr) on .rules and .hero-grid to match, delete the spare spans, and adjust the grid-column values further down.

  • Dimension labels are any element with data-count="284". Optional data-pad="2" zero-pads and data-suffix=" mm" appends a unit. The final value is also the text content, so the label is correct with JavaScript off.
  • Headline words are <span class="word">. Each slides in from one column's width; add or remove words freely.
  • word--red colours a word in the accent. Use it only at display size (see Palette).
  • The bleeding plate is figure.bleed. Its margin-right is what runs it off the sheet; set it to 0 to keep it inside the margin.

The brief — data-brief

A quiet spread. The red hairline (data-rule-red) draws across the full width once, on scroll. Delete the two aside.margin-note blocks if you do not want marginalia here.

The plate field — data-plates

Four plates, four fixed compositions. Each composition is a block of CSS:

Code snippet omitted: it ships with the download.

  • Change a composition by editing those grid-column / grid-row values. Nothing in the JavaScript needs to know.
  • Add a fifth composition by copying a block, changing "a" to "e", adding 'e' to the order array in initPlates, and adding a fifth .comp button with data-comp="e".
  • Add a plate by copying a button.plate and giving it the next data-plate number plus placement in each composition block.
  • The horizontal rules are positioned in percentages per composition (.wall[data-arrangement="b"] .rule-h:nth-child(1) { top: 40%; }) and the script tweens them between the old and new positions.

Clicking a plate makes it lead the field. The composition numbers do the same thing from a single control, and both are real <button> elements, so the whole interaction works from the keyboard with Tab and Enter or Space.

The programme band — data-programme

The only inverted section. Rows are list items with four cells; the fourth (.sched-tag) is the price or status. On narrow screens the row folds into a date column and a stacked description.

The type specimen — data-specimen

One oversized letterform overrunning the left margin. Change the text in p.glyph to any two characters; if you use wider letterforms, reduce the clamp() maximum on .glyph.

The entry form — data-entry

Ruled fields rather than boxes. The form has no action, so point it at your own endpoint or form service.

The marginalia rail — data-rail

Fixed to the outer column above 1100px and to a slim bar under the masthead below it. Above 1100px the column is transparent apart from a 3px paper stripe carrying the margin rule, so full-bleed elements run under it and off the screen while the rail overprints them; see Palette for why its type is backed. It reads its content from the sections themselves:

Code snippet omitted: it ships with the download.

Add those two attributes to any section and it joins the rail. Delete a section and its note goes with it. The rail is aria-hidden because it repeats information already in the page.

Palette

The whole site is three colours. Everything else — rules, dimmed copy, tick marks, washes — is one of the three at another opacity, mixed from the -rgb triples rather than written as an rgba() literal. That is the only reason a reskin is a short edit.

Change these six values in :root and the site is yours:

Code snippet omitted: it ships with the download.

Change each hex and its triple in step, or the hairlines and the dimmed body copy will still be mixed from the old colour.

Measured contrast, and one rule to keep

Measured as used, composited, at the size each pair is set:

Pair Ratio Used for
ink on paper 13.95:1 headings, display type
ink at .72 (--ink-dim) on paper 6.05:1 body copy
paper on ink 13.95:1 the programme band, plate captions
paper at .72 (--paper-dim) on ink 7.63:1 secondary copy in the band
red on paper 4.12:1 numerals and display words only
red on ink / ink on red 3.39:1 display sizes only
ink on a plate (duotone, shadow → highlight) 1.10:1 → 3.39:1 nothing: fails everywhere
paper on a plate (same range) 4.12:1 → 15.35:1 nothing unbacked: fails at the highlight end

The red is a display colour, not a reading colour. At 4.12:1 on paper it clears the 3:1 floor for large text (24px, or 18.66px bold) and misses the 4.5:1 floor for body text, so it letters the section numerals, the hero numeral, the fact keys and the hairlines, and never a sentence. Red is not used as text on ink at any size, and it never sits directly on a photograph: plate captions sit on a solid ink strip and are set in paper.

Nothing is set directly on a plate. A duotone plate runs from near-black to the accent, and across that range neither ink nor paper clears the body floor at every pixel. The marginalia rail is the only type on the page that crosses a plate — above 1100px the rail column is transparent so the hero plate runs underneath it and off the edge of the screen — so the rail's type and its measured rule carry a solid paper backing and keep their 13.95:1 and 6.05:1. Only the empty column is transparent; if you remove that backing the rail becomes unreadable the moment it crosses a photograph.

--ink-faint (3.68:1) is a non-text token. It draws hairlines and tick marks, which are non-text UI at a 3:1 floor, and nothing readable is ever set in it.

If you repaint, re-measure the dimmed variants, not just the base pair: they are what carries the body copy.

Type

--font-display is Archivo Narrow (headings, numerals, dimension labels) and --font-margin is Cardo (marginalia, the statement, the side-notes). Both come from Google Fonts via the two <link> tags in the head; swap the link and the two tokens together.

The scale ratio is the design: --step-display is 100px at its maximum and --step-tick is 10px, so the sheet runs at 10:1 from the largest type to the smallest. Move those two together or that tension disappears.

Images

The photographs in assets/img/ are bundled, optimised WebP derivatives with the template's duotone grade baked into the pixels, which is what makes the set read as one campaign rather than as mixed stock.

  • bleed.webp — 1920×1080, the full-bleed hero plate
  • plate-01.webp … plate-04.webp — 1000×1250 portrait, the plate field

assets/img-manifest.json records the source of each photograph, its output size and the exact grade applied (full desaturation, then a luminance-preserving tint of the same #C4342A used by the rules and numerals). Keep it if you want to regenerate the set after changing the accent; the original photo URLs in it are the credits for the bundled derivatives.

To use your own photographs, replace the files in assets/img/ with the same filenames. Every image is object-fit: cover inside a sized box, so you do not have to match the dimensions exactly, and every photo has a solid ink background-color beneath it so the composition holds while the files load. The grade works best on high-contrast, graphic images; a busy full-colour photograph will muddy once it is reduced to two inks.

Photo credits

The originals are royalty-free photographs from Unsplash. What ships in assets/img/ are altered, graded derivatives, not the originals; these are the source files each one was baked from, and re-running the manifest fetches them again.

Accessibility

  • No JavaScript: every word on the page is readable. The grid is drawn, the headline is set, and the plates sit in the first composition. A blocked GSAP CDN produces exactly the same result, because the script removes the has-js gate when GSAP is missing.
  • Reduced motion: prefers-reduced-motion: reduce gives a designed static page through both a CSS block and a gsap.matchMedia branch. Nothing is invisible and nothing is only reachable through an animation. The rail still reports scroll position, without easing.
  • Keyboard: the plates and the composition numbers are real buttons with aria-pressed, so the field reflows from the keyboard exactly as it does from the pointer. Focus styles are drawn in the accent, and there is a skip link to the content.
  • Touch: nothing depends on hover. The plate captions, which slide up on hover, are legible in their resting position too.

Smooth Scroll

Lenis is wired in and is opt-out. Add data-smooth="off" to <html> to ship without it, or append ?smooth=off to the URL to compare. It is off automatically under reduced motion. Deleting the Lenis script tag and the initLenis block at the bottom of script.js removes it entirely; every ScrollTrigger on the page is correct either way.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.