Image
Describe an image once. Get the srcset, sizes and
<source> tags the browser needs to download the right file for
every screen.
Any backend
You write the URL your CDN or CMS expects. No adapters.
Resizes if needed
No image service? sharp does it: at build time or on request.
Any framework
Returns plain data for React, Vue, Astro, or plain HTML.
Installation#
No dependencies. Add sharp only if the library should resize images
itself (project files,
sharp).
Quick start#
-
Point to the image
Put
{width}where your server expects the size. Give the original size so nothing is upscaled and the layout doesn't jump. -
Say how wide it's displayed
The browser picks a file before the page is laid out, so it needs to know the display width. That's
sizes. -
Render it
Result:
Set defaults once for the whole project:
How it works#
A phone downloads a small file and a 4K screen downloads a large one, from the
same HTML. Try it: change the preset, sizes, or resize the window.
Edit the URL
Candidates
Generated HTML
Where do your images come from?#
For a choice of files, something has to produce each size. Find your case and follow its recipe:
URL template
Your image service already resizes. Write its URL with tokens where the values go. The library fills them in for each width and format.
Tokens: {width}, {height}, {format},
{quality}, {name|default}.
All tokens →
Image proxy
The URLs are plain (photo.jpg, no size in them), but your host
resizes on the fly. Set a proxy: a template where
{src} is the original URL.
Project files
Images live in your code (src/assets). Add ?responsive to
the import, and the Vite plugin makes every size with sharp. The dev server
generates them on the fly. The build writes them as hashed files.
Per image: ./hero.jpg?widths=400;800&formats=webp&responsive.
For types, add /// <reference types="@60fps/ui-image/client" />.
Resize with sharp
Plain URLs, and no image service at all. sharp does the resizing, in one of two ways:
At build or render time
Static sites, SSR. Files are written to a folder.
On request
Any page, even rendered in the browser. Like Astro's /_image.
The endpoint only reads files inside roots, and remote hosts must be
listed in domains. It isn't an open proxy.
Astro
Astro already resizes with its own getImage. Hand it the work:
Sizes & breakpoints#
Describe sizes per breakpoint, with the same numbers as your CSS. The
library writes the media queries in the right order.
Breakpoints are Tailwind's by default. Use your own:
A wrong sizes costs you
Too big and the browser downloads too much. Too small and the image is blurry. Try both in the demo.
Art direction#
A different crop per screen size, not just a different resolution. Each entry
becomes a <source media> with its own width and height.
Good to know#
-
Above the fold? Use
priorityfor the hero image: - Shrinking the window doesn't switch to a smaller file. Browsers keep the bigger image they already have. Test small sizes with a fresh reload.
-
Only list formats your server can make. The browser picks a
<source>by type, and doesn't fall back if that file fails. (Public wsrv.nl has no AVIF, for example.) - Changed the Vite plugin config? Restart the dev server or Storybook: plugins are only read at startup.
-
Built in: never upscales, skips variants with a different
crop, and sets
width/heightso the layout doesn't shift.