home / projects / photography-portfolio
Case 06 / 06 · Content-Disposition: inline; filename=light.jpg
A photographer's portfolio where the images stay the point.
Photography sites fail in two directions: so heavy they're abandoned before loading, or so compressed the work looks worse than it is. This Flask build treated performance as the core design problem — and kept the chrome out of the photographs' way.
- Project
- Client website
- Role
- Full-stack developer
- Timeline
- 2023 — 2024
- Stack
- Flask · Python · JavaScript · CMS
The brief
A working photographer needed a portfolio that made booking enquiries easy and full-resolution work look the way it does on their own monitor — with albums they could reorganise themselves as the body of work grew.
The constraints
- Hundreds of large originals, growing monthly. Serving originals to a grid page is a non-starter; visible quality loss is equally disqualifying.
- Grid stability: images arriving late must not shove the layout around — cumulative layout shift is fatal on an image site.
- The photographer curates, not the developer: album creation, ordering and cover selection had to be self-serve.
- Lightbox accessibility: keyboard navigation, focus containment, escape to close — galleries are where a11y usually gets dropped.
The build
- Derivative pipeline on upload: Flask generates thumbnail, display and full-view sizes the moment an image lands, so the grid serves small files and the lightbox serves exactly what the viewport needs — originals stay archival.
- Layout-stable lazy loading: explicit dimensions and aspect-ratio boxes reserve space before pixels arrive; below-the-fold images load natively lazily; the first grid rows load eagerly so the page never opens empty.
- A lightbox worth using: arrow-key navigation, preloading of adjacent frames, trapped focus, and
Escbehaving like it should. - Enquiry flow with a paper trail: validated Flask forms, honeypot protection, enquiries stored server-side and forwarded by email — a delivery failure never silently eats a booking.
The framing that guided every call: on a portfolio, the interface is overhead. Every decision — type, spacing, motion — was judged by whether it pushed attention toward the photographs or stole from them.
The outcome
Albums load quickly on mobile data, the grid never jumps, and the photographer runs their own catalogue end to end.