OpenCapture › Blog › How full-page screenshots work
How it worksHow full-page screenshots actually work — and the four ways they break
A browser can only ever photograph the part of a page currently on screen. Every “full page” screenshot is therefore several photographs glued together — and almost all of the interesting bugs live in the glue.
The short version. Capture scrolls the page, photographs each viewport, and stitches the slices onto one canvas. Four things go wrong: sticky headers repeat in every slice, lazy images get photographed before they load, inner scroll regions are never scrolled at all, and device-pixel rounding leaves hairlines at every seam. There is a one-minute test further down that catches all four.
The loop, and exactly where it breaks
Strip away the details and every implementation is the same four steps, repeated until you reach the bottom of the document:
- Scroll to the next vertical offset.
- Photograph whatever is currently visible — that is one slice.
- Advance the offset by one viewport height.
- Draw every slice onto a single canvas, in order, and export it.
Write that and you will have something working in an afternoon. Point it at a real website and it falls apart within about thirty seconds, in four distinct ways. Each has a recognisable symptom, so once you know them you can tell at a glance which one you are looking at.
1. The navigation bar appears six times
An element with position: sticky or position: fixed stays glued to
the viewport, which means it is present in every slice. Stitch them and the header
marches down the finished image like a flipbook, with the real content sliced up between the
repetitions.
The fix is to hide those elements for the duration of the capture and restore them afterwards. It sounds obvious; a surprising number of tools skip it. The same applies to cookie banners, chat bubbles, newsletter popups and back-to-top buttons.
Hiding everything with position: fixed is too blunt. A sticky header is
genuinely part of the page and should appear once, at the top, where it belongs.
2. Half the images are grey boxes
Images that load when they enter the viewport need a moment to arrive. Scroll, capture and scroll again with no pause and you photograph the placeholder instead of the picture.
This is the most common cause of a screenshot that looks obviously wrong to a human but is hard to describe. The page looked fine while you were reading it, because you scrolled at human speed and everything had time to load.
A correct implementation scrolls, waits for the network and layout to settle, and only then captures. That is slower — which is exactly why not everything does it.
3. The table only shows four rows
A page can contain its own scrolling regions: a data table with a fixed height, a code block,
a chat panel, a sidebar with overflow: auto. Those are separate scroll contexts.
A full-page capture scrolls the document; it does not scroll them.
So the outer page comes out complete while the inner region shows only whatever happened to be visible. There is no universal fix — a tool has to detect scrollable descendants and decide what to do about each one, and very few do. Worth knowing so you can spot it rather than assume the capture is complete.
4. Thin lines of duplicated pixels at every seam
This one produces the strangest artefacts. On a HiDPI display the browser renders at 2× or 3×. Scroll offsets are expressed in CSS pixels; the captured bitmap is in device pixels. Mix the two anywhere in the arithmetic and every slice lands a fraction off.
The result is a hairline of duplicated or missing pixels at each boundary. You usually notice it first as text that looks subtly wrong — a line of type carrying a sliver of the line above it. Zoom to 400% at a boundary and it is unmistakable.
The arithmetic that matters: a slice’s destination has to be computed as
round(index × viewportHeight × devicePixelRatio), in device pixels.
Using the CSS-pixel height directly is what puts the hairlines there.
A fifth problem, on very long pages only
Browsers cap how large a single canvas surface can be. On Chrome that is 32,767px on any one dimension, with a total area ceiling of 268,435,456px. Exceeding either does not raise an error — the canvas silently becomes unusable and draw calls turn into no-ops, so you get a blank or truncated image with nothing in the console to explain it.
Anything that captures genuinely long pages therefore has to split the output into segments rather than allocating one enormous surface. In practice that means a very tall capture arrives as several PNGs, or as a multi-page PDF.
A one-minute test for any tool
Find a page with a sticky header, lazy images, an inner scroll region and roughly 8,000 pixels of height — most documentation sites qualify. Capture it, then check four things:
| Check | What a failure looks like | Cause |
|---|---|---|
| Header count | The nav bar appears more than once | Sticky elements not hidden |
| Images below the fold | Grey placeholder boxes | No wait for lazy loading |
| Inner regions | A table showing only the rows that were on screen | Nested scroll context |
| Seams at 400% zoom | Thin repeated or missing lines | CSS vs device pixel rounding |
A tool that survives that will survive your actual work.
Where the browser’s built-in feature sits
Both Chrome and Firefox can already do this without an extension. In Chrome, open DevTools,
press Ctrl+Shift+P, type screenshot and
choose Capture full size screenshot. In Firefox, right-click the page and choose
Take Screenshot → Save full page.
It gives you a PNG and nothing else — no annotation, no blurring, no PDF — and it is not especially careful about the failure modes above. For a lot of people that is genuinely enough, and it is worth knowing before you install anything.
How OpenCapture handles each of these
OpenCapture hides sticky and fixed elements for the duration of the capture and restores them afterwards, waits for lazy content to settle before each slice, and computes every slice offset in device pixels so seams stay pixel-exact across device pixel ratios. Captures longer than the canvas ceiling are split automatically into multiple images, or paginated into a PDF. Stitching and all image processing run locally in a Rust/WebAssembly core — nothing about the page is uploaded anywhere.
Nested scroll containers remain the one case no tool solves universally. The section above tells you how to spot it.
Common questions
Why does my screenshot show the navigation bar several times?
The tool captured each viewport without hiding elements that use position: sticky
or position: fixed, so the header appears in every slice and repeats down the
stitched image.
Why are images below the fold grey boxes?
Lazy-loaded images had not finished arriving when the slice was captured. A tool that waits for the network and layout to settle before each capture avoids this.
What are the thin lines running across my stitched screenshot?
Seam artefacts caused by mixing CSS pixels with device pixels when computing scroll offsets. They are most visible on HiDPI displays, where the browser renders at 2× or 3×.
Why did a very long page come back as several images?
Browsers cap the size of a single canvas — on Chrome, 32,767px on one dimension and 268,435,456px of total area. Past that the canvas silently stops working, so long captures are split into segments or paginated into a PDF.